역에의한 계산으로 근속년수, 경력 년월일 구하기 JAVA,JAVASCRIPT
근속년수, 근속년한, 경력인정기간, 경력계산, 년월일 구하기.
날짜 이슈 해결하기
시작
- 정확한 년/월/일 표기 산정기준을 잘 모르겠고, 타 사이트(네이버, 기간계산기, 경력계산기 등..) 다 다름.
2. 민법 제160조 역에 의한 계산 따르기로 함.
3. Java의 LocalDate를 사용하기 위함임. 즉 LocalDate로 계산한 결과에 대한 근거가 민법 제160조 역에 의한 계산방식(약간의 계산 수정은 필요함)
무엇보다도, 계산 결과에 대한 근거를 제시할 수 있다는 점에서 이 방식을 택했다.
시스템 계산과 역에 의한 계산의 차이
1. 시스템계산
- CASE 12022.12.30 ~ 2023.02.28 : 1개월 30일 2023.01.01 ~ 2023.02.28 : 2개월
- 2023.01.02 ~ 2023.02.28 : 1개월 27일
- 2022.12.31 ~ 2023.02.28 : 1개월 29일
- 2022.12.29 ~ 2023.02.28 : 2개월
- CASE 22023.01.02 ~ 2023.04.30 : 3개월 29일
- 2022.12.01 ~ 2023.08.31 : 9개월
2. 역에 의한 계산
- CASE 12022.12.30 ~ 2023.02.28 : 2개월 2023.01.01 ~ 2023.02.28 : 2개월
- 2023.01.02 ~ 2023.02.28 : 1개월 27일
- 2022.12.31 ~ 2023.02.28 : 2개월
- 2022.12.29 ~ 2023.02.28 : 2개월
- CASE 22023.01.02 ~ 2023.04.30 : 3개월 29일
- 2022.12.01 ~ 2023.08.31 : 9개월
계산방법 및 기준 정하기
- 초일 산입
- 역에 의한 계산
- 공무원보수등의 업무지침 (12쪽 사례 1, 사례 2)는 제외함.
- 일반적인 공무원 경력계산식에는 포함되어 있으나, 사기업에서 따를 필요 없음.
역에 의한 계산이란?
예제
2023.01.30 ~ 2023.02.28
→ ③ 월 또는 연으로 정한 경우에 최종의 월에 해당일이 없는 때에는 그 월의 말일로 기간이 만료한다.
3항 적용
= 역에 의한 계산에 의해 시작일의 일자가 종료일에 없는 경우 종료일의 말일까지만 쳐줌
즉 이 경우 (2023.01.30 ~ 2023.02.28) 01.30, 01.31을 세지 않음
따라서
- 2023.01.29 ~ 2023.02.28
- 2023.01.30 ~ 2023.02.28
- 2023.01.31 ~ 2023.02.28
은 2월을 고려한 예외규정인 160조 3항에 의해 1개월로 계산함
프로그램은 어떻게 짜야하나
JAVA
import java.util.*;
import java.lang.*;
import java.io.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate startDate = LocalDate.parse("20230201", dateFormatter);
LocalDate endDate = LocalDate.parse("20230228", dateFormatter).plusDays(1);
StringBuilder diffDate = new StringBuilder();
// 초일산입 근속연수 (하루 더한 결과)
int diffYears = startDate.until(endDate).getYears();
int diffMonths = startDate.until(endDate).getMonths();
int diffDays = startDate.until(endDate).getDays();
// 전월 말일
int lastDayOfMonth = endDate.minusMonths(1).lengthOfMonth();
// 예외케이스 1.30 ~ 3.30 로 인 시작일 종료일의 일자 비교구문 추가
if (startDate.getDayOfMonth() > lastDayOfMonth && startDate.getDayOfMonth() > endDate.getDayOfMonth()) {
diffDays -= 1;
}
if (diffYears > 0) {
diffDate.append(diffYears).append("년 ");
}
if (diffMonths > 0) {
diffDate.append(diffMonths).append("개월 ");
}
diffDate.append(diffDays).append("일");
System.out.println(diffDate.toString());
}
}
LocalDate의 until 메서드를 사용하였음.
Javascript Moment.js 이용한 계산
const moment = require('moment');
const until = (stDt, edDt) => {
/* 실제 계산에 종료일이 포함되지 않기때문에 1일을 더함. */
const startDate = moment(stDt, 'YYYYMMDD');
const endDate = moment(edDt, 'YYYYMMDD').add(1, 'days')
/* 시작 종료일의 년과, 달의 차를 구한다 */;
const totalMonths = endDate.diff(startDate, 'months') % 12;
const totalYears = Math.floor(endDate.diff(startDate, 'months') / 12);
const calcMonths = moment(startDate).add(totalYears, 'years').add(totalMonths, 'months');
let totalDays = endDate.diff(calcMonths, 'days');
console.log(stDt + "~" + edDt)
console.log("totalMonths : ", totalMonths)
console.log("calcMonths : ", calcMonths.format('YYYYMMDD'));
console.log("totalDays : ", totalDays)
// 보정 처리: 시작 날짜가 전월 말일보다 크면 일 수를 하나 감소.
const lastDayOfPrevMonth = endDate.clone().subtract(1, 'months').endOf('month').date();
if (startDate.date() > lastDayOfPrevMonth && startDate.date() > endDate.date() ) {
totalDays--;
}
let text = [];
if (totalYears > 0) text.push(`${totalYears}년`);
if (totalMonths > 0) text.push(`${totalMonths}개월`);
if (totalDays > 0) text.push(`${totalDays}일`);
return text.join(' ');
};
console.log(until('20230630', '20230828'));
/**
* 일의 차이를 구하기위해
* 년의 차이 달의 차이를 통해 새로운 기준점을 만든다.
* 2023.01.21 ~ 2024.05.05 의 년월 차이만 따지고 보면 1년(totalYears), 4개월차이이다.
* 여기서 종료일의 일자(05일)가 시작일의 일자(21일) 보다 앞에 있으므로, 달의 차이에서 1을 뺀다.
* 그럼 달의 차이는 3개월(totalMonths)
* 2024.04.21(calcMonths) 이 만들어짐,
* 이 날짜로부터 종료일 2024.05.05 까지를 달력을 기준으로 세어보면 15일 이 나온다.
* 그리고 여기서 연의차이, 달의차이, 일의 차이를 가져온다.
* 1, 3, 15
*/
// console.log(until('20220131', '20220301'));
// console.log(until('20220131', '20220302'));
// console.log(until('20221201', '20230831'));
// console.log(until('20230102', '20230430'));
// console.log(until('20230505', '20250702'));
// console.log(until('20230121', '20240505'));
console.log(until('20230131', '20230228'));
/**
* 일의 차이를 구하기위해
* 년의 차이 달의 차이를 통해 새로운 기준점을 만든다.
* 2023.01.31 ~ 2023.02.28 의 년월 차이만 따지고 보면 0년(totalYears), 1개월 차이이다.
* 20230131~20230228
totalMonths : 1
calcMonths : 20230228
totalDays : 1
* 여기서 종료일의 일자(28일)가 시작일의 일자(31일) 보다 앞에 있으므로, 달의 차이에서 1을 뺄 것 같지만 이는 이미 한달이 완성된 상태로 보기 때문에 빼지않는다.
* 달의 차이는 여전히 1개월(totalMonths)
* totalMonths 가 더해진 날짜는 2023.02.31 이어야 겠지만 그런 날짜는 없으므로
* 2023.02.28(calcMonths) 이 만들어짐,
* 이날짜로부터 종료일 2023.02.28 까지를 달력을 기준으로 세어보면 1일 이 나온다.
* 여기서 역에의한 계산에 의해서 01.31 ~ 02.28 은 이미 1개월로 계산이 끝났다. 그래서 28일은 계산에서 빼줘야함.
*/
console.log(until('20220131', '20220301'));
/**
* 일의 차이를 구하기위해
* 년의 차이 달의 차이를 통해 새로운 기준점을 만든다.
* 2023.01.31 ~ 2023.03.01 의 년월 차이만 따지고 보면 0년(totalYears), 2개월 차이이다.
* 20220131~20220301
totalMonths : 1
calcMonths : 20220228
totalDays : 2
* 여기서는 종료일의 일자(01일)가 시작일의 일자(31일) 보다 앞에 있으므로 1개월을 빼고
* 그럼 달의 차이는 1개월(totalMonths)
* totalMonths 가 더해진 날짜는 2023.02.31 이어야 겠지만 그런 날짜는 없으므로
* 2023.02.28(calcMonths) 이 만들어짐,
* 이날짜로부터 종료일 2023.03.01 까지를 달력을 기준으로 세어보면 2일 이 나온다.
* 그리고 여기서 연의차이, 달의차이, 일의 차이를 가져온다.
* 여기서 역에의한 계산에 의해서 01.31 ~ 02.28 은 이미 1개월로 계산이 끝났다. 그래서 28일은 계산에서 빼줘야함.
*/
계산
계산에서 말일은 계산일자에 빠지므로 하루를 더해서 계산했다.
2023.01.30 ~ 2023.03.01(실제로는 2023.02.28까지)
until 메서드에서 계산 시에 아래와 같이 동작함.
- 월의 차이를 계산. 일의 차이를 계산
- 월의 차이가 양수이고 일의 차이가 음수일 경우, 월의 차이를 1 감소하고 일의 차이를 재계산
월의 차이가 음수이고 일의 차이가 양수인 경우, 월의 차이 1 증가하고 일의 차이 -= 종료일의 말일(예외처리)
until 함수의 계산식에 따르면 위의 결과는 2개월 1일
이 계산되는데 역에 의한 계산에 의해 2개월로 조정
int lastDayOfMonth = endDate.minusMonths(1).lengthOfMonth();
if (startDate.getDayOfMonth() > lastDayOfMonth && startDate.getDayOfMonth() > endDate.getDayOfMonth()) {
diffDays -= 1;
}
1일이 더해져서 나오는 케이스는 3월 내내 발생하는데 계산식에 2월이 포함되어 있을 때 발생함.
따라서 전월의 말일과 비교하여 보정처리.
빙 돌아왔지만, 결국 ③항만 코드로 구현해 주면 LocalDate를 이용해서 역에 의한 계산을 통한 년/월/일 산출이 가능해진다. ( 고 생각함 )
테스트코드
package test_project;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
public class TestClass {
@Test
public void 테스트() {
List<Map<String, String>> data = Arrays.asList(
new HashMap<String, String>() {{
put("stDt", "20221229");
put("edDt", "20230228");
put("resDt", "2개월");
}},
new HashMap<String, String>() {{
put("stDt", "20221230");
put("edDt", "20230228");
put("resDt", "2개월");
}},
new HashMap<String, String>() {{
put("stDt", "20221231");
put("edDt", "20230228");
put("resDt", "2개월");
}},
new HashMap<String, String>() {{
put("stDt", "20230101");
put("edDt", "20230228");
put("resDt", "2개월");
}},
new HashMap<String, String>() {{
put("stDt", "20230102");
put("edDt", "20230228");
put("resDt", "1개월 27일");
}},
new HashMap<String, String>() {{
put("stDt", "20221201");
put("edDt", "20230831");
put("resDt", "9개월");
}},
new HashMap<String, String>() {{
put("stDt", "20230130");
put("edDt", "20230302");
put("resDt", "1개월 2일");
}},
new HashMap<String, String>() {{
put("stDt", "20230131");
put("edDt", "20230302");
put("resDt", "1개월 2일");
}},
new HashMap<String, String>() {{
put("stDt", "20230130");
put("edDt", "20230301");
put("resDt", "1개월 1일");
}},
new HashMap<String, String>() {{
put("stDt", "20240128");
put("edDt", "20240229");
put("resDt", "1개월 2일");
}},
new HashMap<String, String>() {{
put("stDt", "20240130");
put("edDt", "20240229");
put("resDt", "1개월");
}},
new HashMap<String, String>() {{
put("stDt", "20240131");
put("edDt", "20240229");
put("resDt", "1개월");
}},
new HashMap<String, String>() {{
put("stDt", "20230330");
put("edDt", "20230401");
put("resDt", "3일");
}},
new HashMap<String, String>() {{
put("stDt", "20230331");
put("edDt", "20230401");
put("resDt", "2일");
}},
new HashMap<String, String>() {{
put("stDt", "20230130");
put("edDt", "20230330");
put("resDt", "2개월 1일");
}}
);
for (Map<String, String> item : data) {
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate startDate = LocalDate.parse(item.get("stDt"), dateFormatter);
LocalDate endDate = LocalDate.parse(item.get("edDt"), dateFormatter).plusDays(1);
StringBuilder diffDate = new StringBuilder();
// 초일산입 근속연수 (하루 더한 결과)
int diffYears = startDate.until(endDate).getYears();
int diffMonths = startDate.until(endDate).getMonths();
int diffDays = startDate.until(endDate).getDays();
// 전월 말일
int lastDayOfMonth = endDate.minusMonths(1).lengthOfMonth();
if (startDate.getDayOfMonth() > lastDayOfMonth && startDate.getDayOfMonth() > endDate.getDayOfMonth()) {
diffDays -= 1;
}
if (diffYears > 0) {
diffDate.append(diffYears).append("년 ");
}
if (diffMonths > 0) {
diffDate.append(diffMonths).append("개월 ");
}
if (diffDays > 0) {
diffDate.append(diffDays).append("일");
}
assertEquals(item.get("resDt"), diffDate.toString().trim());
}
}
}
참고자료
- https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=sotong75&logNo=221163900991
- https://www.officetutor.co.kr/board/Dtype/bfrmvw.asp?f_tn=Dqa_excel_n2&f_bno=126226&page=14&fchk=&fval=
- http://www.e-labor.co.kr/store/data/계속근로년수정리.pdf
- https://www.a-ha.io/questions/431ce020143069808d35c08ba1174092
'개발일지' 카테고리의 다른 글
AST를 활용한 코드내 한글추출 (0) | 2024.12.11 |
---|---|
VSCODE 파일 삭제시 Error: EACCES: permission denied, unlink (0) | 2023.09.04 |
google chrome Lighthouse 에 대해 알아보자 (2) | 2021.06.10 |
모달을 띄울때 생각해야할 부분들 (0) | 2021.05.17 |
Access-Control-Allow-Origin Error (0) | 2020.11.13 |
댓글