資料科學 程式設計 工具類別 資料清理

日期轉換工具-處理各種日期格式

日期轉換工具-處理各種日期格式

1. 簡介

提供了一個 DateConverter 類別,用於處理各種日期格式的轉換,包括:

  • 民國年與西元年(公元年)的轉換
  • 日期字串轉換為整數年、月、日
  • 農曆年與天干地支年的轉換
  • 國曆(西曆)與農曆日期的轉換

這個工具類別可以應用於需要處理不同日期格式的應用程式中,例如:歷史資料分析、多國語言日曆系統等。

2. 程式碼結構

DateConverter 類別包含多個靜態方法,每個方法負責一種日期轉換。

import datetime
from lunardate import LunarDate

class DateConverter:
    """
    日期轉換工具類別,提供多種日期格式的轉換方法。
    """

    # 民國年轉換為西元年
    @staticmethod
    def roc_to_ad(year):
        """將民國年轉換為西元年"""
        if year <= 0:
            raise ValueError("無效的民國年份: 年份必須大於0")
        return year + 1911

    # 西元年轉換為民國年
    @staticmethod
    def year_to_roc(year):
        """將西元年轉換為民國年"""
        if year < 1912:
            raise ValueError("年份不在有效範圍內: 民國年從1912年起始")
        roc_year = year - 1911
        return f"{roc_year}年"

    # 支援的日期格式
    _DATE_FORMATS = ['%Y-%m-%d', '%Y/%m/%d', '%Y年%m月%d日']  # 可擴展支持更多格式

    # 日期字符串轉換為整數型別的年、月、日
    @staticmethod
    def convert_to_int_date(date_str):
        """將日期字符串轉換為整數型別的年、月、日"""
        date = None
        for date_format in DateConverter._DATE_FORMATS:
            try:
                date = datetime.datetime.strptime(date_str, date_format)
                break
            except ValueError:
                pass
        
        if date is None:
            raise ValueError(f"無法解析日期:{date_str},請檢查日期格式是否正確。")

        return date.year, date.month, date.day

    # 農曆年轉天干地支年
    @staticmethod
    def lunar_year_to_gan_zhi(year):
        """將農曆年轉換為天干地支年"""
        tian_gan = "甲乙丙丁戊己庚辛壬癸"
        di_zhi = "子丑寅卯辰巳午未申酉戌亥"
        
        gan_idx = (year - 4) % 10  # 天干循環
        zhi_idx = (year - 4) % 12  # 地支循環

        return tian_gan[gan_idx] + di_zhi[zhi_idx]
    
    # 天干地支年轉換為多個西元年份
    @staticmethod
    def gan_zhi_to_lunar_years(gan_zhi_year):
        """將天干地支年轉換為多個西元年份"""
        tian_gan = "甲乙丙丁戊己庚辛壬癸"
        di_zhi = "子丑寅卯辰巳午未申酉戌亥"
        
        gan = gan_zhi_year[0]
        zhi = gan_zhi_year[1]

        gan_idx = tian_gan.index(gan)
        zhi_idx = di_zhi.index(zhi)

        current_year = datetime.datetime.now().year
        year_list = []
        for i in range(current_year, current_year - 241, -1):  # 遍歷過去240年
            gan_idx_shift = (i - 4) % 10  # 根據天干的周期,向前位移4年
            zhi_idx_shift = (i - 4) % 12  # 根據地支的周期,向前位移4年
            if gan_idx_shift == gan_idx and zhi_idx_shift == zhi_idx:
                year_list.append(i)
            
        return year_list
    
    # 國曆日期轉換為農曆日期
    @staticmethod
    def convert_to_lunar_date(year, month, day):
        """將國曆日期轉換為農曆日期"""
        lunar_date = LunarDate.fromSolarDate(year, month, day)
        return lunar_date

    # 農曆日期轉換為國曆日期
    @staticmethod
    def convert_to_solar_date(year, month, day):
        """將農曆日期轉換為國曆日期"""
        lunar_date = LunarDate(year, month, day)
        return lunar_date.toSolarDate()
  • datetime 模組:用於處理日期和時間相關的操作。
  • lunardate 模組:用於處理農曆日期。

3. 各種日期轉換方法

3.1. 民國年與西元年轉換

  • roc_to_ad(year):將民國年轉換為西元年。
    • 如果輸入的民國年小於等於 0,則引發 ValueError。
    • 西元年 = 民國年 + 1911
  • year_to_roc(year):將西元年轉換為民國年。
    • 如果輸入的西元年小於 1912,則引發 ValueError。
    • 民國年 = 西元年 - 1911
    @staticmethod
    def roc_to_ad(year):
        """將民國年轉換為西元年"""
        if year <= 0:
            raise ValueError("無效的民國年份: 年份必須大於0")
        return year + 1911

    @staticmethod
    def year_to_roc(year):
        """將西元年轉換為民國年"""
        if year < 1912:
            raise ValueError("年份不在有效範圍內: 民國年從1912年起始")
        roc_year = year - 1911
        return f"{roc_year}年"

3.2. 日期字串轉換為整數年、月、日

  • convert_to_int_date(date_str):將日期字串轉換為整數型別的年、月、日。
    • 使用 _DATE_FORMATS 列表中定義的日期格式嘗試解析日期字串。
    • 如果所有格式都無法解析,則引發 ValueError。
    _DATE_FORMATS = ['%Y-%m-%d', '%Y/%m/%d', '%Y年%m月%d日']  # 可擴展支持更多格式

    @staticmethod
    def convert_to_int_date(date_str):
        """將日期字符串轉換為整數型別的年、月、日"""
        date = None
        for date_format in DateConverter._DATE_FORMATS:
            try:
                date = datetime.datetime.strptime(date_str, date_format)
                break
            except ValueError:
                pass

        if date is None:
            raise ValueError(f"無法解析日期:{date_str},請檢查日期格式是否正確。")

        return date.year, date.month, date.day

3.3. 農曆年與天干地支年的轉換

  • lunar_year_to_gan_zhi(year):將農曆年轉換為天干地支年。
    • 使用天干和地支的循環列表計算對應的天干和地支。
  • gan_zhi_to_lunar_years(gan_zhi_year):將天干地支年轉換為可能的西元年份列表。
    • 遍歷過去 240 年,找出符合給定天干地支的年份。
    @staticmethod
    def lunar_year_to_gan_zhi(year):
        """將農曆年轉換為天干地支年"""
        tian_gan = "甲乙丙丁戊己庚辛壬癸"
        di_zhi = "子丑寅卯辰巳午未申酉戌亥"

        gan_idx = (year - 4) % 10  # 天干循環
        zhi_idx = (year - 4) % 12  # 地支循環

        return tian_gan[gan_idx] + di_zhi[zhi_idx]

    @staticmethod
    def gan_zhi_to_lunar_years(gan_zhi_year):
        """將天干地支年轉換為多個西元年份"""
        tian_gan = "甲乙丙丁戊己庚辛壬癸"
        di_zhi = "子丑寅卯辰巳午未申酉戌亥"

        gan = gan_zhi_year[0]
        zhi = gan_zhi_year[1]

        gan_idx = tian_gan.index(gan)
        zhi_idx = di_zhi.index(zhi)

        current_year = datetime.datetime.now().year
        year_list = []
        for i in range(current_year, current_year - 241, -1):  # 遍歷過去240年
            gan_idx_shift = (i - 4) % 10  # 根據天干的周期,向前位移4年
            zhi_idx_shift = (i - 4) % 12  # 根據地支的周期,向前位移4年
            if gan_idx_shift == gan_idx and zhi_idx_shift == zhi_idx:
                year_list.append(i)

        return year_list

3.4. 國曆(西曆)與農曆日期的轉換

  • convert_to_lunar_date(year, month, day):將國曆日期轉換為農曆日期。
    • 使用 LunarDate.fromSolarDate() 方法將國曆日期轉換為 LunarDate 物件。
  • convert_to_solar_date(year, month, day):將農曆日期轉換為國曆日期。
    • 使用 LunarDate() 建立 LunarDate 物件,然後使用 toSolarDate() 方法轉換為國曆日期。
    @staticmethod
    def convert_to_lunar_date(year, month, day):
        """將國曆日期轉換為農曆日期"""
        lunar_date = LunarDate.fromSolarDate(year, month, day)
        return lunar_date

    @staticmethod
    def convert_to_solar_date(year, month, day):
        """將農曆日期轉換為國曆日期"""
        lunar_date = LunarDate(year, month, day)
        return lunar_date.toSolarDate()

4. 使用範例

以下是如何使用 DateConverter 類別中的方法的範例:

from date_converter import DateConverter

# 民國年轉換為西元年
roc_year = 112
ad_year = DateConverter.roc_to_ad(roc_year)
print(ad_year)  # 輸出: 2023

# 西元年轉換為民國年
year = 2023
roc_year = DateConverter.year_to_roc(year)
print(roc_year)  # 輸出: "112年"

# 轉換天干地支年為西元年
gan_zhi_year = "丙辰"
years = DateConverter.gan_zhi_to_lunar_years(gan_zhi_year)
print(years)  # 輸出: [1976, 1916, 1856, 1796]

# 日期字符串轉換為整數型別的年、月、日
date_str = "1976-10-10"
year, month, day = DateConverter.convert_to_int_date(date_str)
print(year, month, day)  # 輸出: 1976 10 10

# 農曆日期轉換為國曆日期
lunar_date = DateConverter.convert_to_lunar_date(2023, 1, 1)
print(lunar_date)  # 輸出: 2023年1月1日的農曆日期

# 國曆日期轉換為農曆日期
solar_date = DateConverter.convert_to_solar_date(2023, 1, 1)
print(solar_date)  # 輸出: 2023年1月1日的國曆日期

5. 程式碼邏輯優化

  • 錯誤處理: 在 roc_to_adyear_to_roc 方法中,對輸入的年份進行驗證,如果無效則引發 ValueError
  • 日期格式管理: 使用 _DATE_FORMATS 列表集中管理支援的日期格式,方便擴展和維護。
  • 程式碼重用: 將天干地支的計算邏輯封裝在 lunar_year_to_gan_zhi 方法中,避免在 gan_zhi_to_lunar_years 方法中重複計算。

6. 總結

DateConverter 類別提供了一組方便的日期轉換工具,可以處理多種日期格式。程式碼結構清晰,易於理解和維護。同時,程式碼中包含錯誤處理、日期格式管理和程式碼重用等優化措施,提高了程式碼的可靠性和可擴展性。