WPF를 이용해 네이버가 제공하는 날짜 계산 기능을 구현해 보려 합니다.
(날짜 계산은
기준일을 1일로 포함하여 계산 됩니다)
위와 비슷한 형태로 구현을 하기 위해 필요한 기능이 무엇인지 확인 해볼께요.
- 달력에서 날짜 선택 시 [기준년월일]에 자동 입력
- [기준년월일] 유효성 검사
- [기준년월일]로 부터 날짜 더하기
- [기준년월일]로 부터 날짜 빼기
- [기준년월일]로 부터 기간 구하기
이렇게 필요할 듯 합니다.
이제 하나 하나 알아보도록 하겠습니다.
달력에서 날짜 선택 시 [기준년월일]에 자동 입력
Calendar 컨트롤과 기준년월일 입력에 필요한 텍스트 박스를 XAML 마크업을 이용해 선언 한 뒤 Calendar 컨트롤에서 SelectedDatesChanged 이벤트를 등록 합니다.
1: <Calendar x:Name="calendar" BorderThickness="0" SelectedDatesChanged="Calendar_SelectedDatesChanged"/>
유저가 날짜 선택 시 기준년월일에 선택 된 날짜를 텍스트 박스 Text 속성에 대입합니다.
1: /// <summary>
2: /// 달력 컨트롤의 선택 날짜가 변경 되었을 경우 지정일에 선택된 날짜를 입력 합니다.
3: /// </summary>
4: /// <param name="sender"></param>
5: /// <param name="e"></param>
6: private void Calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
7: {
8: if (calendar.SelectedDate.HasValue)
9: {
10: DateTime selectedItem = calendar.SelectedDate.Value;
11: txtBaseDate.Text = selectedItem.ToString(VALID_DATE_FORMAT);
12: }
13: }
[기준년월일] 유효성 검사
- 최대 길이 10
- 유효한 문자("숫자", ".")만 입력 가능
- 유요한 포맷("yyyy.MM.dd")만 가능
- "숫자"(ex: 20180218) 형식으로 입력 되었을 경우 지정 날짜 포맷으로 변경
유효성에 필요한 상수 선언
1: // 지정 날짜 문자열 최대 길이
2: private const Int32 VALID_DATE_MAX_LENGTH = 10;
3: // 지정 날짜 문자열 포맷
4: private const String VALID_DATE_FORMAT = "yyyy.MM.dd";
5: // 주(Week) 문자열 포맷
6: private const String VALID_DAY_OF_WEEK_FORMAT = "dddd";
7: // 숫자와 .만 가능 패턴
8: private const String VALID_INPUT_PATTERN = @"[\d.]$";
9: // 유효 날짜 패턴
10: private const String VALID_DATE_PATTERN = @"^\d{4}.\d{2}.\d{2}$";
11: // 날짜 입력 옵션 지원 패턴
12: private const String OPTION_DATE_PATTERN = @"^\d{8}$";
최대 입력 길이 제한
1: txtBaseDate.MaxLength = VALID_DATE_MAX_LENGTH;
문자 입력 시 유효성 체크를 위해 TextChanged 이벤트 선언
1: <TextBox x:Name="txtBaseDate" Grid.Row="1" Grid.Column="0" Margin="0,10" TextChanged="textBox_TextChanged" />
유효하지 않은 문자열 확인
1: /// <summary>
2: /// 입력 후 발생되는 이벤트이다.
3: /// 숫자 또는 .만 가능하도록 확인한다.
4: /// </summary>
5: /// <param name="sender"></param>
6: /// <param name="e"></param>
7: private void textBox_TextChanged(object sender, TextChangedEventArgs e)
8: {
9: TextBox textBox = sender as TextBox;
10: string input = textBox.Text;
11: // 유효한 문자열 확인
12: if (Regex.IsMatch(input, VALID_INPUT_PATTERN) == false)
13: {
14: // 이전 문자열로 변경
15: textBox.Text = StringToPrevPosition(input);
16: textBox.CaretIndex = textBox.Text.Length;
17: }
18: }
이전 문자열로 변경
1: /// <summary>
2: /// 문자열을 이전으로 되돌립니다.
3: /// </summary>
4: /// <returns></returns>
5: private string StringToPrevPosition(string str)
6: {
7: return str.Substring(0, str.Length - 1);
8: }
유효한 포맷 확인 및 옵션 지원 포맷 확인
1: // 입력 문자열이 비어있는지 확인
2: if (string.IsNullOrEmpty(txtBaseDate.Text))
3: {
4: List<Inline> textBlockString = CreateGuideText();
5: txtResult.Inlines.AddRange(textBlockString);
6: return;
7: }
8: // yyyyMMdd 포맷인지 확인
9: if (Regex.IsMatch(txtBaseDate.Text, OPTION_DATE_PATTERN))
10: {
11: string validDateString = OptionDateStringToValidDateString(txtBaseDate.Text);
12: // 텍스트 박스의 문자열을 유요한 문자열로 변경
13: txtBaseDate.Text = validDateString;
14: txtBaseDate.CaretIndex = validDateString.Length;
15: }
16: // 유요한 포맷인지 확인
17: if (Regex.IsMatch(txtBaseDate.Text, VALID_DATE_PATTERN))
18: {
19: // 이 곳에서 날짜 계산 처리
20: }
오늘 기준으로 [기준년월일] 기간 확인
기준년월일 문자열 속성 정의
1: /// <summary>
2: /// 지정일 문자열을 날짜 형식으로 변경합니다.
3: /// </summary>
4: public DateTime? InputDate
5: {
6: get
7: {
8: if (string.IsNullOrEmpty(txtBaseDate.Text)) return null;
9: DateTime date = DateTime.MinValue;
10: if (DateTime.TryParse(txtBaseDate.Text, out date)) return date;
11: else return null;
12: }
13: }
시작 날짜가 종료 날짜보다 크거나 같은지 여부
1: /// <summary>
2: /// 시작 날짜가 종료 날짜보다 크거나 같은지 여부
3: /// </summary>
4: /// <param name="startDate"></param>
5: /// <param name="endDate"></param>
6: /// <returns></returns>
7: private bool IsSwap(DateTime startDate, DateTime endDate)
8: {
9: return (startDate >= endDate);
10: }
시작 날짜와 종료 날짜의 기간을 계산합니다.
1: /// <summary>
2: /// 시작 날짜와 종료 날짜의 기간을 계산합니다.
3: /// </summary>
4: /// <param name="startDate"></param>
5: /// <param name="endDate"></param>
6: /// <returns></returns>
7: private TimeSpan CalculatorDateTerm(DateTime startDate, DateTime endDate)
8: {
9: if (IsSwap(startDate, endDate))
10: {
11: DateTime tempDate = startDate;
12: startDate = endDate;
13: endDate = tempDate;
14: }
15: return endDate.Subtract(startDate);
16: }
기준일로부터 ?일째 되는 날 구하기
1: /// <summary>
2: /// 지정일로부터 날짜를 더합니다.
3: /// </summary>
4: /// <param name="sender"></param>
5: /// <param name="e"></param>
6: private void btnAddDay_Click(object sender, RoutedEventArgs e)
7: {
8: DateTime? dt = InputDate;
9: string addDay = txtAddDay.Text;
10: if (dt.HasValue && !string.IsNullOrEmpty(addDay))
11: {
12: DateTime addDate = dt.Value.AddDays(Convert.ToDouble(addDay));
13: txtAddDayResult.Text = addDate.ToString("yyyy.MM.dd");
14: }
15: }
기준일로부터 D-?일 구하기
1: /// <summary>
2: /// 지정일로부터 날짜를 뺍니다.
3: /// </summary>
4: /// <param name="sender"></param>
5: /// <param name="e"></param>
6: private void btnSubtract_Click(object sender, RoutedEventArgs e)
7: {
8: // 지정일부터 몇 일전
9: DateTime? dt = InputDate;
10: string subtractDay = txtSubtractDay.Text;
11: if (dt.HasValue && !string.IsNullOrEmpty(subtractDay))
12: {
13: DateTime subtractDate = dt.Value.AddDays(-Convert.ToDouble(subtractDay));
14: txtSubtractResult.Text = subtractDate.ToString("yyyy.MM.dd");
15: }
16: }
기준일로부터 ?까지는 며칠 째 구하기
1: /// <summary>
2: /// 지정일과 입력된 날짜의 일 간격을 계산 합니다.
3: /// </summary>
4: /// <param name="sender"></param>
5: /// <param name="e"></param>
6: private void btnTerm_Click(object sender, RoutedEventArgs e)
7: {
8: // 지정일로부터 기간
9: if (Regex.IsMatch(txtTermDay.Text, VALID_DATE_PATTERN))
10: {
11: DateTime? dt = InputDate;
12: DateTime startDate = DateTime.MinValue;
13: if (DateTime.TryParse(txtTermDay.Text, out startDate) && dt.HasValue)
14: {
15: TimeSpan term = CalculatorDateTerm(startDate, dt.Value);
16: int totalDay = term.Days;
17: totalDay = IsSwap(startDate, dt.Value) ? (totalDay += 1) : (totalDay * -1);
18: txtTermResult.Text = string.Format("{0}일째", totalDay);
19: }
20: }
21: }
최종 결과
댓글
댓글 쓰기