golang의 이전 달 계산으로 인해 생산이 중단될 수 있는 방법


Renee French가 만든 "A Journey With Go"의 삽화.

내가 작업하고 있는 응용 프로그램 중 하나에서 주어진 날짜의 이전 달이 무엇인지 계산해야 합니다. 쉬운 것 같죠? Golang은 AddDate 메서드가 있는 time package을 제공합니다.

이전에는 C#, Python 및 (한동안) TypeScript로 작업했습니다. 이러한 모든 언어에는 시간을 계산하는 방법도 있습니다. 그들이 어떻게 작동하는지 봅시다.

C# .NET 5:



System.DateTime.AddMonths을 사용해보자:

using System;

public class Program
{
    public static void Main()
    {
        var endOfMay = new DateTime(2021, 05, 31, 12, 00, 00);
        var endOfApril = endOfMay.AddMonths(-1);
        var enfOfJune = endOfMay.AddMonths(1);
        Console.WriteLine("End of May: {0}", endOfMay);
        Console.WriteLine("End of April: {0}", endOfApril);
        Console.WriteLine("End of June: {0}", enfOfJune);
    }
}


산출:

End of May: 05/31/2021 12:00:00
End of April: 04/30/2021 12:00:00
End of June: 06/30/2021 12:00:00


좋아보여요 👍

파이썬 3.9



여기서는 dateutil.relativedelta을 사용합니다.

import datetime
from dateutil.relativedelta import relativedelta

end_of_may = datetime.datetime(2021, 5, 31, 12, 0, 0, 0)
end_of_april = end_of_may + relativedelta(months=-1)
end_of_june = end_of_may + relativedelta(months=1)
print(f'End Of May: {end_of_may}')
print(f'End Of April: {end_of_april}')
print(f'End of June: {end_of_june}')


로그를 보자:

End Of May: 2021-05-31 12:00:00
End Of April: 2021-04-30 12:00:00
End of June: 2021-06-30 12:00:00


내가 찾던 바로 그 것 👌

가다



이제 내 서비스를 중단한 코드:

package main

import (
    "fmt"
    "time"
)

func main() {
    endOfMay := time.Date(2021, 5, 31, 12, 00, 00, 00, time.UTC)
    endOfApril := endOfMay.AddDate(0, -1, 0)
    endOfJune := endOfMay.AddDate(0, 1, 0)
    fmt.Printf("End of May: %s\n", endOfMay)
    fmt.Printf("End of April: %s\n", endOfApril)
    fmt.Printf("End of June: %s\n", endOfJune)
}


그리고 출력:

End of May: 2021-05-31 12:00:00 +0000 UTC
End of April: 2021-05-01 12:00:00 +0000 UTC
End of June: 2021-07-01 12:00:00 +0000 UTC


🤔 🤔 🤔
뭔가 잘못되었다...
... 그리고 정확히 2021년 5월 31일 내 프로젝트에서 생산에 일어났습니다. 이 코드 조각은 생산을 중단했습니다. 웃기게도, 딱 하루만 망가졌으니까. 그리고 앞으로 며칠, 7월 말까지는 다시 잘 작동할 것입니다.
AddDate의 이러한 동작은 저에게 전혀 예상치 못한 일이었습니다. 나는 그것을 한 것에 대해 Go를 비난하고 싶었지만... 나는 나 자신을 탓할 수 밖에 없습니다 😅 왜냐하면 documentation of AddDate method에서 다음을 찾을 수 있기 때문입니다.

AddDate normalizes its result in the same way that Date does, so, for example, adding one month to October 31 yields December 1, the normalized form for November 31.



Python 및 C# 🤷‍♂️에 대한 내 경험에서 기대했던 것과는 다릅니다. 그러나 문서화되었습니다. 그래서- 내 잘못 😕

테이크아웃



마지막으로 미래에서 여러분과 저를 위한 3가지 테이크아웃:
  • 문서를 읽는 것이 유용할 수 있습니다 😄





    야콥 ☘️\u0000










    6시간의 디버깅으로 문서 읽기 시간을 5분 단축할 수 있습니다.


    오후 12:38 - 2021년 5월 12일









  • 극단적인 경우에 대한 테스트를 작성합니다.
  • 프로그래밍 세계에서 날짜를 처리하는 것은 힘든 일입니다.

  • Postscriptum - TypeScript



    TypeScript는 Go와 같은 일을 합니다.

    const endOfMay: Date = new Date(2021, 4, 31, 12, 0, 0, 0); // months are starting from 0 here 🤦
    console.log(`End of May: ${endOfMay}`);
    const endOfApril = new Date(endOfMay);
    endOfApril.setMonth(endOfMay.getMonth() - 1);
    console.log(`End of April: ${endOfApril}`);
    const endOfJune = new Date(endOfMay);
    endOfJune.setMonth(endOfMay.getMonth() + 1);
    console.log(`End of June: ${endOfJune}`);
    


    산출:

    End of May: Mon May 31 2021 12:00:00 GMT+0200 (Central European Summer Time)
    End of April: Sat May 01 2021 12:00:00 GMT+0200 (Central European Summer Time)
    End of June: Thu Jul 01 2021 12:00:00 GMT+0200 (Central European Summer Time)
    


    그러나 dayjs은 이를 완벽하게 처리합니다.

    import dayjs from "dayjs";
    
    const endOfMayDate = new Date(2021, 4, 31, 12, 0, 0, 0);
    const endOfMay = dayjs(endOfMayDate);
    console.log(`End of May: ${endOfMay}`);
    const endOfApril = dayjs(endOfMayDate).add(-1, "month");
    console.log(`End of April: ${endOfApril}`);
    const endOfJune = dayjs(endOfMayDate).add(1, "month");
    console.log(`End of June: ${endOfJune}`);
    


    산출:

    End of May: Mon, 31 May 2021 10:00:00 GMT 
    End of April: Fri, 30 Apr 2021 10:00:00 GMT 
    End of June: Wed, 30 Jun 2021 10:00:00 GMT 
    

    좋은 웹페이지 즐겨찾기