DateTimePicker (일자시각선택)
Va.DateTimePicker — 날짜 + 시간을 한 필드에 입력받는 캘린더 팝업
Va.DatePicker에 시간(시:분:초)까지 추가된 컴포넌트. 2024-12-25 14:30:00 형태로 날짜와 시간을 하나의 필드에서 다룹니다. 캘린더 팝업 UI + 마스킹된 필드 입력, 화면-저장 포맷 분리까지 DatePicker의 특성을 전부 계승합니다.
- 클래스: Va.DateTimePicker — va_component.js:7470
- short name: dateTimePicker
- 상속: Va.PureField (DatePicker와 형제)
- isContainer: true
- 베이스 CSS: va-input (팝업 va-menu-pop, 달력 calendar-inner)
- 소스 크기: 약 828줄

1. 기본 사용
{
tagName: 'dateTimePicker',
value: '20241225143000', // 저장 값: YYYYMMDDHHMMSS 14자리
dateFormat: 'ymd',
timeFormat: 'hhmmss',
onSelect: 'onDateTimeChange'
}
- 화면 표시: 2024-12-25 14:30:00
- 저장 값(getValue()): 20241225143000
- 필드에 직접 타이핑 가능 (마스킹 적용)
2. Va.DatePicker와의 차이
항목Va.DatePickerVa.DateTimePicker
| 입력 대상 | 날짜만 | 날짜 + 시간 |
| 저장 값 길이 | 8자리 (YYYYMMDD) | 14자리 (YYYYMMDDHHMMSS) 또는 12자리 (YYYYMMDDHHMM) |
| 마스킹 | ____-__-__ | ____-__-__ __:__:__ |
| timeFormat | ✕ | ✓ (hhmmss / hhmm / hm) |
| timeSeperator | ✕ | ✓ (: 기본) |
| dateTimeSeperator | ✕ | ✓ ( 기본, 날짜-시간 사이) |
| additionalInfo | ✕ | ✓ (추가 정보) |
| 팝업 UI | 캘린더만 | 캘린더 + 시분초 입력 |
한 줄 요약: "DatePicker + 시간(HH:MM:SS)까지."
3. 주요 속성
날짜 포맷 (DatePicker 계승)
속성기본값설명
| dateFormat | 'ymd' | 화면 날짜 순서 |
| dateSeperator | '-' | 화면 날짜 구분자 |
| valueDateFormat | 'ymd' | 저장 날짜 순서 |
| valueDateSeperator | '' | 저장 날짜 구분자 |
시간 포맷 (신규)
속성기본값설명
| timeFormat | 'hhmmss' | 시간 표시 형식. hhmmss(초 포함) / hhmm(분까지) / hm(분까지 축약) |
| timeSeperator | ':' | 시간 구분자 |
| valueTimeFormat | — | 저장 시간 형식 |
| valueTimeSeperator | — | 저장 시간 구분자 |
날짜-시간 결합
속성기본값설명
| dateTimeSeperator | ' ' (공백) | 화면에서 날짜와 시간 사이 구분자 |
| valueDateTimeSeperator | '' | 저장 값에서 날짜와 시간 사이 구분자 |
범위
속성설명
| min / max | 최소/최대 날짜시간 |
팝업
속성기본값설명
| expanded | false | 팝업 초기 상태 |
| popWidth | 260 | 팝업 폭 |
추가
속성설명
| additionalInfo | 팝업에 부가 정보 표시 |
4. 저장 값 길이 — 핵심 개념
timeFormat에 따라 저장 값 길이가 달라집니다:
timeFormat저장 값 형태길이
| hhmmss (기본) | YYYYMMDDHHMMSS | 14자리 |
| hhmm / hm | YYYYMMDDHHMM | 12자리 |
valueDateSeperator / valueTimeSeperator / valueDateTimeSeperator 지정 시 각 자리에 구분자 삽입:
{
valueDateSeperator: '-',
valueTimeSeperator: ':',
valueDateTimeSeperator: ' '
}
// 저장 값: '2024-12-25 14:30:00'
5. 포맷 조합 예시
한국 표준 (기본)
{ tagName: 'dateTimePicker' }
// 화면: 2024-12-25 14:30:00
// 저장: 20241225143000
분까지만
{
tagName: 'dateTimePicker',
timeFormat: 'hhmm'
}
// 화면: 2024-12-25 14:30
// 저장: 202412251430
ISO 8601 스타일 저장
{
tagName: 'dateTimePicker',
valueDateSeperator: '-',
valueTimeSeperator: ':',
valueDateTimeSeperator: 'T'
}
// 화면: 2024-12-25 14:30:00
// 저장: 2024-12-25T14:30:00
미국식 화면 + 한국식 저장
{
tagName: 'dateTimePicker',
dateFormat: 'mdy',
dateSeperator: '/',
timeFormat: 'hhmm',
valueDateFormat: 'ymd'
}
// 화면: 12/25/2024 14:30
// 저장: 202412251430
6. 이벤트
DatePicker와 동일:
이벤트시그니처발생 시점
| select | (component, element, value, evt) | 팝업에서 값 선택 |
| beforePop / afterPop / hidePop | 팝업 표시/숨김 | |
| expand / collapse | 팝업 확장/축소 | |
| focus / blur | 표준 | |
| change / keydown / keyup | 표준 |
7. 메서드 — 두 벌의 setter/getter
DatePicker와 마찬가지로 값 변환 로직이 두 벌:
메서드설명
| setValue(value) | valueDateFormat/valueTimeFormat 규약 값 세팅 |
| getValue() | 위 규약 형태로 반환. 마스킹 언더스코어가 남아 있으면 '' 반환 (아직 다 안 입력) |
| setRawValue(value) | 항상 YYYYMMDDHHMMSS(또는 YYYYMMDDHHMM) 원시 값 세팅 |
| getRawValue() | 항상 원시 값 반환 |
팝업 제어
메서드설명
| showDateTimePickerPop(evt) / hideDateTimePickerPop() | 팝업 열기/닫기 |
| showPop() | (레거시) |
| hidePop() | expanded=false + update() |
| expand() / collapse() | 팝업 상태 토글 |
| drawCalendar() | 캘린더 재렌더링 |
상태
메서드설명
| setDisabled(bool) / setReadOnly(bool) | PureField 상속 |
| focus() / blur() | 포커스 |
8. getValue()의 특별한 동작 — 부분 입력 방어
timeFormat: 'hhmmss'일 땐 저장 값 총 19자리(구분자 포함), hhmm/hm이면 16자리가 완전한 형태.
필드에 마스킹 언더스코어가 남아 있으면(_) getValue()가 '' 반환 (va_component.js:8202, 8215):
if(tempValue.replaceAll('_', '').length !=19){
return '';
}
의미: 사용자가 2024-12-25 14:__:__처럼 완성 안 된 상태로 폼을 제출해도 getValue()가 부분 값이 아니라 빈 문자열을 돌려줌 → 서버로 이상한 값 전송 방지.
⚠️ 완성됐다고 판단하는 기준이 마스킹 언더스코어 제거 후 길이라서, 사용자가 잘못된 형식으로 완성해도(예: 9999-99-99 99:99:99) getValue()가 그 값을 반환합니다. 별도 검증 필요.
9. 팝업 UI 구조
drawCalendar()가 렌더링:
- 날짜 그리드 (DatePicker와 동일)
- 시간 입력 영역 — 시:분:초 (또는 시:분)
- 오늘/지금 버튼 (buttonToday)
- 년월 이동 (buttonLeft, buttonRight)
- min/max 범위 밖 비활성화
시간 부분은 스피너 또는 텍스트 입력 형태로 조작.
10. 내부 구조
DatePicker와 거의 동일:
<div elname="element" class="va-input [size]..." tag-name="dateTimePicker" field="true">
<div elname="fieldWrapper" class="field-wrapper">
<input elname="field" type="text" placeholder="____-__-__ __:__:__"
style="border:0px">
<div elname="focusLine" class="focus-line"></div>
<div elname="calendarIconWrapper">
<span elname="calendarIcon" class="icon menu ico_calender_ltr">📅</span>
</div>
</div>
<div elname="popDiv" class="menu-button-pop-div">
<div elname="pop" class="va-menu-pop" style="position:absolute; display:none">
<div elname="popInner" class="calendar-inner">
<!-- 캘린더 + 시분초 입력 -->
</div>
</div>
</div>
</div>
11. Va.DateTimePicker vs 관련 컴포넌트
컴포넌트역할
| Va.DatePicker | 날짜만 (YYYYMMDD) |
| Va.DateTimePicker | 날짜 + 시간 (YYYYMMDDHHMMSS) |
| Va.TimePicker | 시간만 |
| Va.YearPicker / Va.MonthPicker | 년도/월만 |
| Va.DateRangePicker | 시작-종료 날짜 범위 |
| Va.DateTimeField | DateTimePicker + Field 래퍼 (라벨/검증) |
12. 언제 쓰나
DateTimePicker가 맞을 때
- 예약·일정 시각 (회의 시작, 배송 시각)
- 게시글 예약 발행 시각
- 로그·이벤트 타임스탬프 편집
- 계약·마감 정확한 시각까지
다른 걸 쓸 때
- 날짜만 → Va.DatePicker
- 시간만 → Va.TimePicker
- 라벨 붙은 폼 필드 → Va.DateTimeField
- 시작-종료 시각 범위 → Va.DateTimeRangePicker(있다면) 또는 두 개 조합
13. 흔한 조합 예시
// 표준 (초까지)
{ tagName: 'dateTimePicker', value: '20241225143000' }
// 분까지
{
tagName: 'dateTimePicker',
timeFormat: 'hhmm',
value: '202412251430'
}
// ISO 8601 저장
{
tagName: 'dateTimePicker',
valueDateSeperator: '-',
valueTimeSeperator: ':',
valueDateTimeSeperator: 'T'
// getValue() → "2024-12-25T14:30:00"
}
// 미국식 화면
{
tagName: 'dateTimePicker',
dateFormat: 'mdy',
dateSeperator: '/',
timeFormat: 'hhmm'
// 화면: 12/25/2024 14:30
}
// 범위 제한 (2024년만)
{
tagName: 'dateTimePicker',
min: '20240101000000',
max: '20241231235959'
}
// 오늘 이후만 (예약)
{
tagName: 'dateTimePicker',
min: new Date().toISOString().slice(0,19).replace(/[-T:]/g,''),
onSelect: 'onReservationTime'
}
14. 알아두면 좋을 주의사항
- 저장 값 길이가 timeFormat에 따라 달라짐 — 14자리(초) / 12자리(분) 헷갈리지 말 것.
- getValue()가 완성 안 된 값에 '' 반환 — 마스킹 언더스코어가 남으면 빈 문자열. 서버 전송 시 유용하지만 검증엔 별도 필요.
- 값 유효성 검증 없음 — 9999-99-99 같은 잘못된 값도 완성되면 그대로 반환.
- setValue()가 유효성 검사 안 함 — 부적절한 값도 그대로 파싱 시도.
- dateFormat과 valueDateFormat 혼동 — 화면 vs 저장. timeFormat도 마찬가지.
- valueDateTimeSeperator가 있어야 저장 값에 구분자 삽입 — 없으면 20241225143000처럼 붙어서 나옴.
- setValue() 로직에 버그성 코드 — valueDateFormat이 mdy/dmy일 때 조건문이 this.dateFormat을 검사 (va_component.js:8115, 8119). valueDateFormat이어야 정확. 특정 조합에서 오동작 가능.
- hm과 hhmm이 같이 취급됨 — 코드에서 두 값 모두 "분까지"로 처리.
- 팝업 상태머신 참여 — 다른 팝업과 자동 상호 배타.
- min/max는 팝업에만 강제 — 필드 직접 타이핑으로 범위 밖 값도 입력 가능.
- 타임존 없음 — 로컬 문자열만. UTC 정확성 중요하면 별도 처리.
- value는 문자열 — Date 객체 넘기면 .replaceAll, .substring 호출에서 크래시.
- setRawValue() 사용 시 timeFormat 반영 — 원시 값 자릿수도 timeFormat에 따라 12/14 자리.
- 팝업 사이즈 — popWidth가 260. 시분초까지 넣기엔 좁을 수 있으니 필요하면 확장.
- additionalInfo 속성 — properties에 선언은 있으나 실제 사용처는 코드 확인 필요.