แปลงปี / เดือน / วันเป็นวันของปีใน Python


127

ฉันใช้โมดูลPython datetimeเช่น:

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

และฉันอยากจะคำนวณวันของปีที่อ่อนไหวของปีอธิกสุรทิน เช่นในวันนี้ (6 มีนาคม 2009) เป็นวันที่ 65 ของปี 2009 web-based เครื่องคิดเลข

อย่างไรก็ตามฉันเห็นสองตัวเลือก:

A. สร้างอาร์เรย์ number_of_days_in_month = [31, 28, ... ] ตัดสินใจว่าเป็นปีอธิกสุรทินหรือไม่รวมวันด้วยตนเอง

B. ใช้datetime.timedeltaเพื่อเดาและค้นหาไบนารีสำหรับวันที่ถูกต้องของปี:

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

ทั้งสองอย่างนี้รู้สึกอึดอัดและฉันรู้สึกว่ามีวิธีคำนวณวันของปีแบบ "Pythonic" มากกว่า ความคิด / ข้อเสนอแนะใด ๆ ?

คำตอบ:


256

มีวิธีง่ายๆดังนี้

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

13
การเพิ่มเนื้อหาเล็กน้อยและอวดรู้ แต่การใช้งานdate.today()แทนที่จะdatetime.now()ได้ผลและเน้นย้ำถึงลักษณะของการดำเนินการอีกเล็กน้อย
Jeremy

5
ยังดีกว่า: time.localtime().tm_yday ไม่จำเป็นต้องแปลงวันที่และเวลาเป็นเวลาเนื่องจากนั่นคือสิ่งที่ localtime () ให้ผล
Mike Ellis

14
@MikeEllis แต่โซลูชันนี้แสดงให้เห็นว่าต้องทำอย่างไรเมื่อวันที่และเวลาไม่ตรงกับวันนี้
gerrit

2
หมายเหตุ:เริ่มนับที่ 1
Mehdi Nellen

1
จะเกิดอะไรขึ้นถ้าฉันต้องการย้อนกลับฉันมีตัวเลขที่บอกว่า "วันที่ 26 ของปี 2020" และฉันต้องการเปลี่ยนเป็นวันที่ "26-01-2020"
Sankar

43

คุณไม่สามารถใช้strftime?

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

แก้ไข

ตามที่ระบุไว้ในความคิดเห็นหากคุณต้องการทำการเปรียบเทียบหรือคำนวณกับตัวเลขนี้คุณจะต้องแปลงเป็นint()เพราะstrftime()ส่งคืนสตริง หากเป็นเช่นนั้นคุณควรใช้คำตอบของ DzinXดีกว่า


1
-1: เหนอะ ที่ดีกว่าคืออัลกอริทึม "วันนี้ลบ 1 มกราคม" สะอาดกว่าและชัดเจนมากโดยไม่ต้องมองหาเรื่องไม่สำคัญเกี่ยวกับ '% j' ของ strftime
ล็อต

12
อย่างจริงจัง? มันเป็นอย่างไรที่น่าเบื่อและการทดแทนในวันที่ 1 มกราคมนี้ไม่ใช่หรือ? มีเหตุผล ฉันไม่เห็นด้วย นี่คือวิธีที่สะอาดกว่าในความคิดของฉัน
Paolo Bergantino

1
การใช้ strftime เป็นการใช้ทางอ้อมเนื่องจากสร้างสตริงจากตัวเลข: สมาชิกตารางเวลา อ่านแหล่งที่มา สตริงที่ผลิตควรถูกแปลงเป็นตัวเลขก่อนการคำนวณ / การเปรียบเทียบดังนั้นทำไมต้องกังวล?
tzot

2
หากใครต้องการวันของปีในสตริงให้พูดว่าใช้ในชื่อไฟล์มากกว่า strftime เป็นวิธีที่สะอาดกว่ามาก
Captain_M

13

คำตอบของ DZinX เป็นคำตอบที่ดีสำหรับคำถามนี้ ฉันพบคำถามนี้ในขณะที่กำลังมองหาฟังก์ชันผกผัน ฉันพบว่าสิ่งนี้ใช้งานได้:

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

ฉันไม่แน่ใจเกี่ยวกับมารยาทในบริเวณนี้ แต่ฉันคิดว่าตัวชี้ไปที่ฟังก์ชันผกผันอาจมีประโยชน์สำหรับคนอื่น ๆ เช่นฉัน


6

ฉันต้องการนำเสนอประสิทธิภาพของวิธีการต่างๆบน Python 3.4, Linux x64 ข้อความที่ตัดตอนมาจาก line profiler:

      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
         (...)

ประสิทธิภาพสูงสุดคือ

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

1
คุณคำนวณประสิทธิภาพอย่างไร ฉันลองใช้ time.time และนั่นคือผลลัพธ์ของฉัน: def f (): (today - datetime.datetime (today.year, 1, 1)) วัน + 1 start = time.time (); f (); พิมพ์ ('Lapsed {}'. format (time.time () - start)); หมดอายุ 5.221366882324219e-05 def f (): int (today.strftime ('% j')); เริ่มต้น = time.time (); f (); พิมพ์ ('Lapsed {}'. format (time.time () - start)); หมดอายุ 7.462501525878906e-05
ssoto

5

ลบวันที่ 1 มกราคมจากวันที่:

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

1
ไม่มีอะไรเทียบกับ Paolo แต่ datetime.timedelta มีหน่วยเป็นวัน (แน่นอนเช่นเดียวกับวินาทีและไมโครวินาที) ดังนั้นจึงเป็นทางเลือกที่เป็นธรรมชาติซึ่งตรงกว่าการจัดรูปแบบสตริงอย่างแน่นอน
zweiterlinde

1
d.toordinal () - วันที่ (d.year, 1, 1) .toordinal () + 1 เป็นมาตรฐานมากขึ้นตามเอกสาร เทียบเท่ากับคำตอบที่ยอมรับโดยไม่ต้องสร้างทูเปิลตลอดเวลา
Dingle

5

หากคุณมีเหตุผลที่จะหลีกเลี่ยงการใช้datetimeโมดูลฟังก์ชันเหล่านี้จะทำงาน

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

รหัสนี้ใช้วันที่เป็นอาร์กิวเมนต์อินพุตและส่งกลับวันของปี

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.