Chuyển đổi năm / tháng / ngày thành ngày trong năm bằng Python


127

Tôi đang sử dụng mô-đun datetime của Python , tức là:

>>> import datetime
>>> today = datetime.datetime.now()
>>> print today
2009-03-06 13:24:58.857946

và tôi muốn tính ngày nhạy cảm của năm nhuận. ví dụ: hôm nay (ngày 6 tháng 3 năm 2009) là ngày thứ 65 của năm 2009. Đây là máy tính DateTime dựa trên web .

Dù sao, tôi thấy một hai lựa chọn:

A. Tạo một số number_of_days_in_month = [31, 28, ...], quyết định xem đó có phải là năm nhuận hay không, tổng hợp theo ngày theo cách thủ công.

B. Sử dụng datetime.timedeltađể đoán và sau đó tìm kiếm nhị phân cho đúng ngày trong năm:

>>> import datetime
>>> YEAR = 2009
>>> DAY_OF_YEAR = 62
>>> d = datetime.date(YEAR, 1, 1) + datetime.timedelta(DAY_OF_YEAR - 1)

Cả hai đều cảm thấy khá cồng kềnh & tôi có cảm giác ruột thịt rằng có một cách tính toán "Pythonic" hơn trong năm. Bất kỳ ý tưởng / đề xuất?

Câu trả lời:


255

Có một giải pháp rất đơn giản:

from datetime import datetime
day_of_year = datetime.now().timetuple().tm_yday

13
Một bổ sung rất nhỏ và được cho là mô phạm, nhưng sử dụng date.today()chứ không phải datetime.now()cũng hoạt động và nhấn mạnh bản chất của hoạt động nhiều hơn một chút.
Jeremy

5
Tốt hơn nữa: time.localtime().tm_yday Không cần phải chuyển đổi thời gian thành thời gian biểu vì đó là những gì localtime () mang lại.
Mike Ellis

14
@MikeEllis Nhưng giải pháp này minh họa những việc cần làm khi datetime không tương ứng với ngày hôm nay.
gerrit

2
lưu ý: điều này bắt đầu đếm lúc 1
Mehdi Nellen

1
Điều gì sẽ xảy ra nếu tôi muốn làm ngược lại, tôi có số cho phép "ngày 26 của năm 2020" và tôi muốn chuyển đổi thành ngày "26-01-2020"?
Sankar

43

Bạn không thể sử dụng strftime?

>>> import datetime
>>> today = datetime.datetime.now()
>>> print today
2009-03-06 15:37:02.484000
>>> today.strftime('%j')
'065'

Biên tập

Như đã lưu ý trong các nhận xét, nếu bạn muốn so sánh hoặc tính toán với số này, bạn sẽ phải chuyển đổi nó thành int()strftime()trả về một chuỗi. Nếu đó là trường hợp, bạn nên sử dụng câu trả lời của DzinX .


1
-1: icky. Tốt hơn là thuật toán "hôm nay trừ ngày 1 tháng 1". Sạch sẽ hơn và hoàn toàn rõ ràng mà không cần tìm kiếm một mẩu chuyện nhỏ về '% j' của strftime
S.Lott

12
Nghiêm túc? Làm thế nào là icky và trừ ngày 1 tháng 1 này không? strftime là có lý do. Tôi không đồng ý. Đây là cách sạch hơn theo ý kiến ​​của tôi.
Paolo Bergantino

1
Sử dụng strftime là gián tiếp, bởi vì nó tạo ra một chuỗi từ một số: thành viên timetuple.tm_yday. Đọc nguồn. Chuỗi được sản xuất nên được chuyển đổi thành một số trước khi tính toán / so sánh, vậy tại sao phải bận tâm?
tzot

2
Nếu một người cần ngày trong năm trong một chuỗi, hãy nói để sử dụng trong tên tệp, hơn strftime là một giải pháp sạch hơn nhiều.
captain_M

13

Câu trả lời của DZinX là một câu trả lời tuyệt vời cho câu hỏi. Tôi tìm thấy câu hỏi này trong khi tìm kiếm hàm nghịch đảo. Tôi thấy điều này để làm việc:

import datetime
datetime.datetime.strptime('1936-077T13:14:15','%Y-%jT%H:%M:%S')

>>>> datetime.datetime(1936, 3, 17, 13, 14, 15)

datetime.datetime.strptime('1936-077T13:14:15','%Y-%jT%H:%M:%S').timetuple().tm_yday

>>>> 77

Tôi không chắc chắn về nghi thức ở đây, nhưng tôi nghĩ rằng một con trỏ đến hàm nghịch đảo có thể hữu ích cho những người khác như tôi.


6

Tôi muốn trình bày hiệu suất của các cách tiếp cận khác nhau, trên Python 3.4, Linux x64. Trích từ hồ sơ dòng:

      Line #      Hits         Time  Per Hit   % Time  Line Contents
      ==============================================================
         (...)
         823      1508        11334      7.5     41.6          yday = int(period_end.strftime('%j'))
         824      1508         2492      1.7      9.1          yday = period_end.toordinal() - date(period_end.year, 1, 1).toordinal() + 1
         825      1508         1852      1.2      6.8          yday = (period_end - date(period_end.year, 1, 1)).days + 1
         826      1508         5078      3.4     18.6          yday = period_end.timetuple().tm_yday
         (...)

Vì vậy, hiệu quả nhất là

yday = (period_end - date(period_end.year, 1, 1)).days

1
Làm thế nào bạn tính toán hiệu suất? Tôi đã thử sử dụng time.time và đó là những kết quả của tôi: def f (): (hôm nay - datetime.datetime (today.year, 1, 1)). Days + 1 start = time.time (); f (); print ('Lapsed {}'. format (time.time () - start)); Mất hiệu lực 5.221366882324219e-05 def f (): int (today.strftime ('% j')); bắt đầu = thời gian.time (); f (); print ('Lapsed {}'. format (time.time () - start)); Mất hiệu lực 7.462501525878906e-05
ssoto

5

Chỉ cần trừ ngày 1 tháng 1 kể từ ngày:

import datetime
today = datetime.datetime.now()
day_of_year = (today - datetime.datetime(today.year, 1, 1)).days + 1

1
Không có gì chống lại Paolo, nhưng datetime.timedelta được tính bằng ngày (cũng như giây và micro giây), do đó, đó là một lựa chọn tự nhiên --- chắc chắn trực tiếp hơn định dạng chuỗi
zweiterlinde

1
d.toordinal () - date (d.year, 1, 1) .toordinal () + 1 là tiêu chuẩn hơn theo tài liệu. Nó tương đương với câu trả lời được chấp nhận mà không tạo ra bộ dữ liệu toàn bộ thời gian.
Đinh lăng

5

Nếu bạn có lý do để tránh sử dụng datetimemô-đun, thì các chức năng này sẽ hoạt động.

def is_leap_year(year):
    """ if year is a leap year return True
        else return False """
    if year % 100 == 0:
        return year % 400 == 0
    return year % 4 == 0

def doy(Y,M,D):
    """ given year, month, day return day of year
        Astronomical Algorithms, Jean Meeus, 2d ed, 1998, chap 7 """
    if is_leap_year(Y):
        K = 1
    else:
        K = 2
    N = int((275 * M) / 9.0) - K * int((M + 9) / 12.0) + D - 30
    return N

def ymd(Y,N):
    """ given year = Y and day of year = N, return year, month, day
        Astronomical Algorithms, Jean Meeus, 2d ed, 1998, chap 7 """    
    if is_leap_year(Y):
        K = 1
    else:
        K = 2
    M = int((9 * (K + N)) / 275.0 + 0.98)
    if N < 32:
        M = 1
    D = N - int((275 * M) / 9.0) + K * int((M + 9) / 12.0) + 30
    return Y, M, D

1

Mã này lấy một ngày làm đối số đầu vào và trả về ngày trong năm.

from datetime import datetime
date = raw_input("Enter date: ")  ## format is 02-02-2016
adate = datetime.datetime.strptime(date,"%d-%m-%Y")
day_of_year = adate.timetuple().tm_yday
day_of_year
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.