DateTimeField (일시필드)
Va.DateTimeField — 라벨 + 캘린더 팝업 + 시간까지
Va.DateTimePicker가 순수 날짜+시간 입력이라면, Va.DateTimeField는 그 위에 라벨·필수 표시·검증 메시지까지 얹은 완성 폼 필드입니다. Field 계열 아키텍처 그대로, 내부에 Va.DateTimePicker를 소유하는 Composition 구조.
- 클래스: Va.DateTimeField — va_component.js:8301
- short name: dateTimeField
- 상속: Va.Field (다른 Field 형제들과 같음)
- 내부 컴포넌트: Va.DateTimePicker 인스턴스 (fieldComponent)
- isContainer: true
- 베이스 CSS: va-field (role="date-field" 자동 부여)

1. 기본 사용
{
tagName: 'dateTimeField',
label: '예약 시각',
value: '20241225143000', // YYYYMMDDHHMMSS
required: true,
onSelect: 'onReservationTimeChange'
}
라벨 + 검증 + 캘린더 팝업 + 시분초 입력이 한 번에 세팅. 사용법은 DateField와 거의 동일하지만 저장 값이 14자리 (또는 12자리) 로 늘어난다는 게 차이.
2. Field 계열에서의 위치
Va.Field
├─ Va.InputField ← Va.Input
├─ Va.SearchField ← Va.Search
├─ Va.NumberField ← Va.Number
├─ Va.ComboboxField ← Va.Combobox
├─ Va.DateField ← Va.DatePicker (날짜만)
├─ Va.DateTimeField ← Va.DateTimePicker ← 이 문서 (날짜+시간)
└─ ...
DateTimeField의 정체: Field 베이스 + 내부에 Va.DateTimePicker 인스턴스.
⚠️ 이름 주의: DateField ← DatePicker, DateTimeField ← DateTimePicker — 다른 Field 형제와 달리 "Picker"가 이름에서 생략됩니다. 등록명은 dateTimeField.
3. Va.DateTimePicker / Va.DateField와의 차이
항목Va.DateTimePickerVa.DateTimeFieldVa.DateField
| 라벨 | ✕ | ✓ | ✓ |
| 검증 메시지 | ✕ | ✓ | ✓ |
| info 툴팁 | ✕ | ✓ | ✓ |
| 날짜 입력 | ✓ | ✓ | ✓ |
| 시간 입력 | ✓ | ✓ | ✕ |
| 저장 값 길이 | 14/12자리 | 14/12자리 | 8자리 |
| role="date-field" 자동 | ✕ | ✓ | ✓ |
한 줄 요약: "폼 안 라벨 붙은 날짜+시간 필드."
4. 주요 속성
날짜 포맷 (DateField와 공통)
속성기본값설명
| dateFormat | 'ymd' | 화면 날짜 순서 — ymd / mdy / dmy |
| dateSeperator | '-' | 화면 날짜 구분자 |
| valueDateFormat | 'ymd' | 저장 값의 날짜 순서 |
| valueDateSeperator | '' | 저장 값의 날짜 구분자 |
시간 포맷 (DateTimeField 전용)
속성기본값설명
| timeFormat | 'hhmmss' | 시간 표시 형식. hhmmss(초 포함) / hhmm(분까지) / hm(분까지 축약) |
| timeSeperator | ':' | 시간 구분자 |
| valueTimeFormat | — | 저장 시간 형식 |
| valueTimeSeperator | — | 저장 시간 구분자 |
날짜-시간 결합
속성기본값설명
| dateTimeSeperator | ' ' (공백) | 화면에서 날짜와 시간 사이 |
| valueDateTimeSeperator | '' | 저장 값에서 날짜와 시간 사이 |
팝업
속성기본값설명
| popWidth | 240 | 팝업 폭 (⚠️ DatePicker/DateTimePicker는 260) |
| expanded | false | 초기 상태 |
| min / max | — | 최소/최대 날짜시간 |
라벨 (Field 상속)
속성설명
| label | 라벨 텍스트 또는 객체 |
| labelPosition | top / bottom / left / right |
| labelWidth | 라벨 폭 |
| noLabel | 라벨 숨김 |
| infoButton | info 아이콘 |
| required | 필수 표시 |
검증
속성설명
| validation | {state, size, message} |
| validationState | success / warning / error |
| validationMessage | 메시지 |
세부 커스터마이즈 (datePicker 옵션 키)
{
tagName: 'dateTimeField',
label: '예약 시각',
datePicker: { // ← 내부 DateTimePicker에 전달
additionalInfo: '...'
}
}
⚠️ 옵션 키가 datePicker — DateField와 같은 키를 씀. dateTimePicker가 아님. 소스에서 복사되며 남은 흔적으로 보임.
각 Field 계열 옵션 키:
- InputField → input
- ComboboxField → combobox
- TagField → tag
- DateField / DateTimeField → datePicker (두 개가 같은 키!)
5. 저장 값 길이 — 핵심 개념
timeFormat에 따라 저장 값 길이가 달라집니다:
timeFormat저장 값 형태길이
| hhmmss (기본) | YYYYMMDDHHMMSS | 14자리 |
| hhmm / hm | YYYYMMDDHHMM | 12자리 |
valueDateSeperator / valueTimeSeperator / valueDateTimeSeperator 지정 시 각 자리에 구분자 삽입:
{
valueDateSeperator: '-',
valueTimeSeperator: ':',
valueDateTimeSeperator: ' '
}
// 저장 값: '2024-12-25 14:30:00'
6. 이벤트
DateTimePicker의 이벤트를 재발화:
이벤트시그니처발생 시점
| select | (component, element, evt) | 팝업에서 값 선택 시 |
| beforePop / afterPop / hidePop | 팝업 표시/숨김 | |
| expand / collapse | 팝업 확장/축소 | |
| focus / blur | 표준 | |
| change / keydown | Field 표준 (검증 자동 리셋) |
⚠️ select 콜백 시그니처가 짧음 — (component, element, evt) 3개 인자만. 값이 필요하면 component.getValue() 별도 호출.
⚠️ DateField와 달리 select 이벤트가 두 번 dispatch되지 않음 — DateField는 중복 dispatch 있었지만 DateTimeField는 한 번만. 실무엔 이 차이가 미미하지만 코드 이식할 때 유의.
7. 메서드 — 오버라이드된 setter/getter
DateField와 동일한 두 벌 setter/getter 패턴:
메서드설명
| setValue(value) | valueDateFormat/valueTimeFormat 규약 값 세팅 |
| getValue() | 위 규약 형태로 반환. 마스킹 언더스코어 남아 있으면 '' 반환 |
상태 (Field 상속)
메서드설명
| setDisabled(bool) / getDisabled() | 비활성화 |
| setReadOnly(bool) / setReadonly(bool) | 읽기 전용 |
| setLabel(label) | 라벨 변경 |
| setPlaceholder(text) | 플레이스홀더 |
| setSize(size) | 크기 |
검증
메서드설명
| setValidation(state, message) | 검증 표시 + aria |
| clearValidation() | 검증 해제 |
포커스
메서드설명
| focus() / blur() | 내부 DateTimePicker의 fieldElement에 위임 |
주의: setRawValue, getRawValue, showPop, hidePop 등 DateTimePicker의 세부 메서드는 위임 없음. 필요하면 component.fieldComponent.xxx()로 직접.
8. 내부 구조
<div elname="element" class="va-field [vertical|horizontal]"
role="date-field" field="true">
<div elname="inner" class="field-inner">
<div elname="labelDiv" class="label-div">
<label cpname="label">예약 시각 <span class="required">*</span></label>
</div>
<div elname="comment" class="field-comment"></div>
<div elname="fieldDiv" class="field-div">
<div cpname="field" class="va-input"> ← 내부 Va.DateTimePicker
<div class="field-wrapper">
<input type="text" placeholder="____-__-__ __:__:__">
<div class="focus-line"></div>
<div class="calendar-icon-wrapper">
<span class="icon menu ico_calender_ltr">📅</span>
</div>
</div>
<!-- 팝업은 hiddenArea로 이동 -->
</div>
</div>
</div>
<div elname="validationDiv" style="display:none">
<div class="va-validation">...</div>
</div>
</div>
9. getValue()의 특별한 동작 — 부분 입력 방어
DateTimePicker에서 상속받은 동작. 필드에 마스킹 언더스코어가 남아 있으면(_) getValue()가 '' 반환:
- timeFormat: 'hhmmss' → 완전한 값은 19자리(구분자 포함), 부족하면 ''
- timeFormat: 'hhmm' → 완전한 값은 16자리, 부족하면 ''
의미: 사용자가 2024-12-25 14:__:__처럼 미완성 상태로 제출해도 서버로 이상한 값이 안 감. 다만 잘못된 형식(9999-99-99 99:99:99)은 걸러지지 않음 — 별도 검증 필요.
10. 언제 쓰나
DateTimeField가 맞을 때
- 폼 안 예약·일정 시각 — 회의 시작 시간, 배송 시각, 게시글 예약 발행
- 로그·이벤트 타임스탬프 편집
- 계약·마감 정확한 시각까지 필요한 필드
- 라벨·필수·검증이 필요한 상황
다른 걸 쓸 때
- 시간 필요 없음 → Va.DateField (8자리, 훨씬 간단)
- 시간만 → Va.TimeField
- 라벨 없는 인라인 → Va.DateTimePicker
- 시작-종료 시각 범위 → Va.DateTimeRangeField(있다면) 또는 두 개 조합
11. 흔한 조합 예시
// 표준 (초까지)
{
tagName: 'dateTimeField',
label: '예약 시각',
value: '20241225143000',
required: true
}
// 분까지만
{
tagName: 'dateTimeField',
label: '회의 시작',
timeFormat: 'hhmm',
value: '202412251430'
}
// ISO 8601 저장
{
tagName: 'dateTimeField',
label: '이벤트 시각',
valueDateSeperator: '-',
valueTimeSeperator: ':',
valueDateTimeSeperator: 'T'
// 저장: '2024-12-25T14:30:00'
}
// 미국식 화면 + 한국식 저장
{
tagName: 'dateTimeField',
label: 'Reservation',
dateFormat: 'mdy',
dateSeperator: '/',
timeFormat: 'hhmm',
valueDateFormat: 'ymd'
// 화면: 12/25/2024 14:30
// 저장: 202412251430
}
// 범위 제한 (오늘 이후만, 예약)
{
tagName: 'dateTimeField',
label: '희망 배송 시각',
min: new Date().toISOString().slice(0,19).replace(/[-T:]/g,''),
onSelect: 'onDeliveryChange'
}
// 좌측 라벨 + 필수
{
tagName: 'dateTimeField',
label: '시작 시각',
labelPosition: 'left',
labelWidth: 100,
required: true
}
// info 툴팁
{
tagName: 'dateTimeField',
label: '마감 시각',
infoButton: {
tooltip: 'KST 기준 시각입니다'
}
}
12. 알아두면 좋을 주의사항
- 컴포넌트명 주의 — dateTimeField (not dateTimePickerField).
- value는 문자열 — Date 객체 넘기면 크래시.
- 저장 값 길이가 timeFormat에 따라 달라짐 — 14자리(초) / 12자리(분) 헷갈리지 말 것.
- getValue()가 미완성 값에 '' 반환 — 마스킹 언더스코어 있으면 빈 문자열.
- 값 유효성 검증 없음 — 9999-99-99 99:99:99 같은 잘못된 값도 완성되면 그대로 반환. 별도 검증 필요.
- dateFormat과 valueDateFormat 혼동 — 화면 vs 저장.
- timeFormat과 valueTimeFormat 혼동 — 마찬가지로 화면 vs 저장.
- 옵션 키가 datePicker — DateField와 같은 키. 헷갈리지 말 것.
- popWidth 기본 240 — DatePicker/DateTimePicker(260)와 다름. 데이트타임 팝업은 좀 좁은 편.
- 일부 메서드 위임 누락 — setRawValue/getRawValue/showPop/hidePop 등. fieldComponent로 직접.
- role="date-field" 자동 부여 — DateTime이지만 role은 date-field. ARIA 힌트.
- setValue() 로직에 버그성 코드 — DateTimePicker와 동일하게 valueDateFormat이 mdy/dmy일 때 조건문이 this.dateFormat을 검사 (va_component.js:8455, 8459). 특정 조합에서 오동작 가능.
- 팝업 상태머신 참여 — 다른 팝업과 자동 상호 배타.
- min/max는 팝업 UI에만 강제 — 필드 직접 타이핑으로 범위 밖 값 입력 가능.
- 타임존 없음 — 로컬 문자열만.
13. 실전 예 — 예약 시각 폼
class ReservationForm extends Va.View {
mounted() {
// 최소 시각을 지금으로 설정
const now = new Date();
const minStr = now.getFullYear() +
String(now.getMonth()+1).padStart(2, '0') +
String(now.getDate()).padStart(2, '0') +
'000000';
this.getRef('startTime').min = minStr;
}
onSubmit(btn, el, evt) {
const start = this.getRef('startTime').getValue();
if (!start) {
this.getRef('startTime').setValidation('error', '시작 시각을 입력하세요');
return;
}
// 서버로 전송 (14자리 문자열)
ReservationService.save(this, { startTime: start }, this.onSaved);
}
onSaved(view, ok, res) {
if (ok) {
new Va.Alert({ title: '완료', message: '예약되었습니다' }).show(view);
}
}
config() {
return {
tagName: 'page',
tags: [{
tagName: 'panel',
tags: [
{ tagName: 'h2', innerHTML: '예약 등록' },
{
tagName: 'dateTimeField',
label: '시작 시각',
ref: 'startTime',
required: true,
timeFormat: 'hhmm', // 분까지만
infoButton: { tooltip: '오늘 이후 시각으로 지정' }
},
{
tagName: 'inputField',
label: '메모',
ref: 'memo'
},
{
tagName: 'button',
text: '예약',
appearance: 'primary',
onClick: 'onSubmit'
}
]
}]
};
}
}
14. dateTimeField vs dateField 선택 기준
상황추천
| 생년월일·계약일 (시간 무의미) | dateField |
| 예약 시각·회의 시작 (시간 중요) | dateTimeField |
| 시간대별 로그·이벤트 편집 | dateTimeField |
| 마감일 (하루 단위) | dateField |
| 마감 시각 (분·초까지) | dateTimeField |
| 서버가 시각도 요구하지만 UI는 날짜만 | dateField + 서버 저장 시 T00:00:00 부착 |
필요 없으면 dateField를 쓰세요. 시각 입력 UI는 사용자에게 부담이 있어, 시간이 정말 필요할 때만 dateTimeField.