본문 바로가기
개발일지

역에의한 계산으로 근속년수, 경력 년월일 구하기 JAVA,JAVASCRIPT

by 새우하이 2023. 8. 3.

역에의한 계산으로 근속년수, 경력 년월일 구하기 JAVA,JAVASCRIPT 

근속년수, 근속년한, 경력인정기간, 경력계산,  년월일 구하기.

날짜 이슈 해결하기

시작

  1. 정확한 년/월/일 표기 산정기준을 잘 모르겠고, 타 사이트(네이버, 기간계산기, 경력계산기 등..) 다 다름.

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개월

계산방법 및 기준 정하기

  1. 초일 산입
  2. 역에 의한 계산
  3. 공무원보수등의 업무지침 (12쪽 사례 1, 사례 2)는 제외함.
    • 일반적인 공무원 경력계산식에는 포함되어 있으나, 사기업에서 따를 필요 없음.

역에 의한 계산이란?

예제

2023.01.30 ~ 2023.02.28

→ ③ 월 또는 연으로 정한 경우에 최종의 월에 해당일이 없는 때에는 그 월의 말일로 기간이 만료한다.

3항 적용

= 역에 의한 계산에 의해 시작일의 일자가 종료일에 없는 경우 종료일의 말일까지만 쳐줌

즉 이 경우 (2023.01.30 ~ 2023.02.28) 01.30, 01.31을 세지 않음

따라서

  1. 2023.01.29 ~ 2023.02.28
  2. 2023.01.30 ~ 2023.02.28
  3. 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. 월의 차이를 계산. 일의 차이를 계산
  2. 월의 차이가 양수이고 일의 차이가 음수일 경우, 월의 차이를 1 감소하고 일의 차이를 재계산
  3. 월의 차이가 음수이고 일의 차이가 양수인 경우, 월의 차이 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());
        }
	}
	
}

참고자료

 

댓글