Konversi Tahun / Bulan / Hari ke Hari Tahun dalam Python

127

Saya menggunakan modul datetime Python , yaitu:

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

dan saya ingin menghitung hari tahun yang peka terhadap tahun kabisat. misal hari ini (6 Maret 2009) adalah hari ke-65 tahun 2009. Berikut ini adalah kalkulator DateTime berbasis web .

Lagi pula, saya melihat dua opsi:

A. Buat array number_of_days_in_month = [31, 28, ...], putuskan apakah ini tahun kabisat, jumlah hari secara manual.

B. Gunakan datetime.timedeltauntuk membuat perkiraan & pencarian biner untuk hari yang benar tahun ini:

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

Keduanya terasa kikuk & aku punya firasat bahwa ada cara yang lebih "Pythonic" untuk menghitung hari dalam setahun. Ada ide / saran?

Pete
sumber

Jawaban:

256

Ada solusi yang sangat sederhana:

from datetime import datetime
day_of_year = datetime.now().timetuple().tm_yday
DzinX
sumber
13
Tambahan yang sangat kecil dan bisa dibilang pedantic, tetapi menggunakan date.today()daripada datetime.now()juga bekerja dan menekankan sifat operasi sedikit lebih.
Jeremy
5
Lebih baik lagi: time.localtime().tm_yday Tidak perlu mengubah datetime menjadi jadwal karena itulah yang dihasilkan oleh localtime ().
Mike Ellis
14
@ MikeEllis Tapi solusi ini menggambarkan apa yang harus dilakukan ketika datetime tidak sesuai dengan hari ini.
gerrit
2
catatan: ini mulai dihitung pada 1
Mehdi Nellen
1
bagaimana jika saya ingin melakukan yang sebaliknya, saya memiliki nomor katakanlah "hari ke 26 tahun 2020", dan saya ingin mengubahnya menjadi tanggal "26-01-2020"?
Sankar
43

Tidak bisa Anda gunakan strftime?

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

Edit

Seperti disebutkan dalam komentar, jika Anda ingin melakukan perbandingan atau perhitungan dengan nomor ini, Anda harus mengonversinya int()karena strftime()mengembalikan sebuah string. Jika itu masalahnya, Anda lebih baik menggunakan jawaban DzinX .

Paolo Bergantino
sumber
1
-1: icky. Lebih baik adalah algoritma "hari ini minus 1 Januari". Jauh lebih bersih dan sangat jelas tanpa mencari sepele tentang strftime's '% j'.
S.Lott
12
Serius? Bagaimana ini Januari 1 icky dan subtracting tidak? strftime ada karena suatu alasan. Saya hanya tidak setuju. Ini WAY bersih menurut saya.
Paolo Bergantino
1
Menggunakan strftime tidak langsung, karena menghasilkan string dari nomor: timetuple.tm_yday anggota. Baca sumbernya. String yang dihasilkan harus dikonversi ke angka sebelum perhitungan / perbandingan, jadi mengapa repot?
tzot
2
Jika seseorang membutuhkan hari dalam setahun dalam sebuah string, katakan untuk digunakan dalam nama file, daripada strftime adalah solusi yang jauh lebih bersih.
captain_M
13

Jawaban DZinX adalah jawaban yang bagus untuk pertanyaan itu. Saya menemukan pertanyaan ini sambil mencari fungsi terbalik. Saya menemukan ini berfungsi:

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

Saya tidak yakin dengan etiket di sini, tapi saya pikir pointer ke fungsi terbalik mungkin berguna untuk orang lain seperti saya.

Dave X
sumber
6

Saya ingin menyajikan kinerja berbagai pendekatan, pada Python 3.4, Linux x64. Kutipan dari profiler garis:

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

Jadi yang paling efisien adalah

yday = (period_end - date(period_end.year, 1, 1)).days
omikron
sumber
1
Bagaimana Anda menghitung kinerja? Saya mencoba menggunakan time.time dan itu adalah hasil saya: def f (): (hari ini - datetime.datetime (today.year, 1, 1)). Hari + 1 start = time.time (); f (); print ('Lapeded {}'. format (time.time () - mulai)); Lapsed 5.221366882324219e-05 def f (): int (today.strftime ('% j')); start = time.time (); f (); print ('Lapeded {}'. format (time.time () - mulai)); Lapsed 7.462501525878906e-05
ssoto
5

Cukup kurangi tanggal 1 Januari dari tanggal:

import datetime
today = datetime.datetime.now()
day_of_year = (today - datetime.datetime(today.year, 1, 1)).days + 1
zweiterlinde
sumber
1
Tidak ada yang melawan Paolo, tetapi datetime.timedelta ditentukan dalam beberapa hari (serta detik dan mikrodetik, tentu saja), jadi itu adalah pilihan alami --- tentu saja lebih langsung daripada pemformatan string
zweiterlinde
1
d.toordinal () - date (d.year, 1, 1) .toordinal () + 1 lebih standar sesuai dengan dokumentasi. Ini setara dengan jawaban yang diterima tanpa menghasilkan tuple sepanjang waktu.
Dingle
5

Jika Anda memiliki alasan untuk menghindari penggunaan datetimemodul, maka fungsi-fungsi ini akan berfungsi.

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
Barry Andersen
sumber
1

Kode ini mengambil tanggal sebagai argumen input dan mengembalikan hari dalam setahun.

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
Gajanan Kothawade
sumber