Извличане на ден от годината и юлиански ден от низова дата

Имам низ "2012.11.07" в python. Трябва да го преобразувам в обект за дата и след това да получа цяло число на ден от годината, а също и юлиански ден. Възможно ли е?


person f.ashouri    schedule 18.12.2012    source източник
comment
Не се нарича юлиански ден, ако просто искате номера на деня за годината. en.wikipedia.org/wiki/Ordinal_date   -  person Douglas G. Allen    schedule 20.01.2017


Отговори (8)


Първо, можете да го конвертирате в обект datetime.datetime по този начин:

>>> import datetime
>>> fmt = '%Y.%m.%d'
>>> s = '2012.11.07'
>>> dt = datetime.datetime.strptime(s, fmt)
>>> dt
datetime.datetime(2012, 11, 7, 0, 0)

След това можете да използвате методите на datetime, за да получите това, което искате... с изключение на това, че datetime няма функцията, която искате директно, така че трябва да конвертирате в кортеж за време

>>> tt = dt.timetuple()
>>> tt.tm_yday
312

Терминът "юлиански ден" има няколко различни значения. Ако търсите 2012312, трябва да направите това индиректно, например едно от следните.

>>> int('%d%03d' % (tt.tm_year, tt.tm_yday))
2012312
>>> tt.tm_year * 1000 + tt.tm_yday
2012312

Ако търсите различно значение, трябва да можете да го разберете от тук. Например, ако искате значението „дни от 1 януари 4713 г. пр. н. е.“ и имате формула, която изисква григорианска година и ден в годината, имате тези две стойности по-горе, за да включите. (Ако имате формула, която отнема григорианска година, месец и ден, дори не се нуждаете от стъпката timetuple.) Ако не можете да разберете накъде да отидете оттам, попитайте за допълнителни подробности.

Ако нямате формула – и може би дори ако вече имате – най-добрият ви залог вероятно е да потърсите PyPI и ActiveState за вече съществуващи модули. Например, едно бързо търсене откри нещо, наречено jdcal. Никога не го бях виждал преди, но едно бързо pip install jdcal и кратък преглед на readme и успях да направя това:

>>> sum(jdcal.gcal2jd(dt.year, dt.month, dt.day))
2456238.5

Това е същият резултат, който USN преобразувателят на юлиански дати ми даде.

Ако искате интегрален юлиански ден, вместо дробна юлианска дата, трябва да решите в коя посока искате да закръглите – към 0, към отрицателна безкрайност, закръгляне на обяд до следващия ден, закръгляне на обяд към четни дни и т.н. (Имайте предвид, че Юлианската дата се определя като започваща от обяд на 1 януари 4713 г. пр.н.е., така че половината от 7 ноември 2012 г. е 2456238, другата половина е 2456239 и само вие знаете кое от тях искате...) Например, за да закръглите към 0:

>>> int(sum(jdcal.gcal2jd(dt.year, dt.month, dt.day)))
2456238
person abarnert    schedule 18.12.2012
comment
юлиански ден е цяло число. gcal2jd() връща юлианска дата. - person jfs; 14.09.2014
comment
@J.F.Sebastian: Прочетете свързаните документи. Юлианските дати се съхраняват в две числа с плаваща запетая (double). jdcal връща дробни юлиански дни (приема се обяд, ако е дадена само дата). Ако искате да спорите, че тези дни не трябва да се наричат ​​Юлиански дни, а нещо друго, обсъдете го с автора на модула. - person abarnert; 15.09.2014
comment
ваша отговорност е да се уверите, че модулът, който вие предложи, връща това, което OP иска. - person jfs; 15.09.2014
comment
@J.F.Sebastian: Добре, добавих кода за повикване на int. Но целта не е да му дадете OP кода, който той може да използва без да мисли, или да препоръчате конкретна библиотека; Използвах gdcal като пример за видовете библиотеки, които можете да намерите с бързо търсене в Google, PyPI или ActiveState; все още зависи от OP да направи това търсене, да оцени библиотеките и да избере тази, която иска. - person abarnert; 15.09.2014
comment
може би е по-добре да се приеме обяд, дадена дата, вместо полунощ на предишния ден, т.е. трябва да е 39, както в моя отговор, а не 38. Вашето мнение е валидно, но не би ли било по-добре да предоставите резултатите от изследването в отговора, ако е възможно, за да избегнете принуждаването на хората да го дублират. - person jfs; 15.09.2014
comment
@J.F.Sebastian: Резултатите от изследването бяха буквално търсене PyPI julian, щракнете върху първия ред, прегледайте бегло неговия readme, pip install jdcal, стартирайте един от примерите от readme, проверете дали изглежда разумно. Що се отнася до закръгляването... Добре, ще го включа и в отговора. - person abarnert; 15.09.2014
comment
pico-nitpick: номерът на юлианския ден е цяло число. Юлианската дата по своята същност е дробна: Юлианската дата (JD ) за всеки момент е номерът на юлианския ден за предходния обяд плюс частта от деня след този момент. - person jfs; 16.09.2014
comment
проблемът с лекия изследователски подход е, че календарните изчисления могат да бъдат измамно прости. Ако не ви интересуват нюанси, които могат да бъдат пренебрегнати в повечето ситуации, тогава можете да използвате изричната формула като в моя отговор. Възможните грешки се разкриват по този начин. Разбирам, че повечето въпроси за повечето хора не изискват добре проучен отговор. - person jfs; 16.09.2014
comment
@J.F.Sebastian: Добре, така че не ми е ясно с какво не си съгласен. Няма уникален юлиански ден, съответстващ на определена дата - вместо това има половината от един юлиански ден и половината от друг. Кой е правилният зависи от това какво се опитва да направи приложението. И когато започвате само с низ от дата, отговорът на този въпрос е еквивалентен на въпроса как да закръглите юлианска дата до юлиански ден за вашето приложение, нали? Последният ми абзац не предава ли това достатъчно ясно? Ако не, какво трябва да променя? - person abarnert; 16.09.2014
comment
ние сме в споразумение тук. - person jfs; 16.09.2014

За да получите юлианския ден, използвайте метода datetime.date.toordinal и добавете фиксирано отместване.

Юлианският ден е броят на дните от 1 януари 4713 г. пр. н. е. в 12:00 часа в пролептичния юлиански календар или 24 ноември 4714 г. пр. н. е. в 12:00 часа в пролептичен григориански календар. Имайте предвид, че всеки юлиански ден започва на обяд, а не в полунощ.

Функцията toordinal връща броя на дните от 31 декември 1 г. пр. н. е. в 00:00 ч. в пролептичния григориански календар (с други думи, 1 януари 1 г. сл. н. е. в 00:00 ч. е началото на ден 1, а не ден 0). Обърнете внимание, че 1 пр. н. е. директно предшества 1 сл. н. е., не е имало година 0, тъй като числото нула е изобретено едва много векове по-късно.

import datetime

datetime.date(1,1,1).toordinal()
# 1

Просто добавете 1721424,5 към резултата от toordinal, за да получите юлианския ден.

Друг отговор вече обяснява как да анализирате низа, с който сте започнали, и да го превърнете в datetime.date обект. Така че можете да намерите юлианския ден, както следва:

import datetime

my_date = datetime.date(2012,11,7)   # time = 00:00:00
my_date.toordinal() + 1721424.5
# 2456238.5
person ghostarbeiter    schedule 18.08.2016

За да опростите началните стъпки на отговора на abarnert:

from dateutil import parser
s = '2012.11.07'
dt = parser.parse(s)

след това приложете останалата част от отговора на abanert.

person K.-Michael Aye    schedule 04.01.2013
comment
коя версия на питон е това? tm_yday не е там за мен @ 2.7 - person Curtis Price; 12.06.2013
comment
за мен е. Забравихте ли да преобразувате в timetuple? обектът dt няма член tm_yday, докато обектът time.struct_time, който получавате от dt.timetuple(), има този член. - person K.-Michael Aye; 13.06.2013

Тази функционалност (преобразуване на низове от дата в юлианска дата/час) присъства и в модула astropy. Моля, вижте тяхната документация за пълни подробности. Имплементацията на астропията е особено удобна за лесни преобразувания към час по Юлиан, за разлика само от датата по Юлиан.

Примерно решение за първоначалния въпрос:

>>> import astropy.time
>>> import dateutil.parser

>>> dt = dateutil.parser.parse('2012.11.07')
>>> time = astropy.time.Time(dt)
>>> time.jd
2456238.5
>>> int(time.jd)
2456238
person Kyle    schedule 18.02.2015

За бързи изчисления можете да намерите ден от годината и номер на юлианския ден, като използвате само stdlib datetime модул:

#!/usr/bin/env python3
from datetime import datetime, timedelta

DAY = timedelta(1)
JULIAN_EPOCH = datetime(2000, 1, 1, 12) # noon (the epoch name is unrelated)
J2000_JD = timedelta(2451545) # julian epoch in julian dates

dt = datetime.strptime("2012.11.07", "%Y.%m.%d") # get datetime object
day_of_year = (dt - datetime(dt.year, 1, 1)) // DAY + 1 # Jan the 1st is day 1
julian_day = (dt.replace(hour=12) - JULIAN_EPOCH + J2000_JD) // DAY
print(day_of_year, julian_day)
# 312 2456239

Друг начин да получите day_of_year:

import time

day_of_year = time.strptime("2012.11.07", "%Y.%m.%d").tm_yday

julian_day в кода по-горе е "номерът на юлианския ден, свързан с слънчев ден -- номерът, присвоен на ден при непрекъснато броене на дни, започващи с номер 0 на юлианския ден, присвоен на деня, започващ в Гринуичкия среден обяд на 1 януари 4713 г. пр. н. е., Юлиански пролептичен календар -4712".

time документацията на модула използва термина "Julian day" различно:

Jn Юлианският ден n (1 ‹= n ‹= 365). Високосните дни не се броят, така че през всички години 28 февруари е ден 59, а 1 март е ден 60.
n Юлианският ден, базиран на нула (0 ‹= n ‹= 365). Броят се високосните дни и е възможно да се отнесе към 29 февруари.

т.е. нулевият юлиански ден е day_of_year - 1 тук. И първият (Jn) е day_of_year - (calendar.isleap(dt.year) and day_of_year > 60) -- дните, започващи с 1 март, се изместват, за да се изключи високосният ден.

Има и свързан термин: юлианска дата. Номерът на юлианския ден е цяло число. Юлианската дата по своята същност е дробна: " Юлианската дата (JD) за всеки момент е номерът на юлианския ден за предходния обяд плюс частта от деня след този момент."

Като цяло, за да избегнете сами обработката на крайни случаи, използвайте библиотека за изчисляване на юлианския ден, както предложено от @abarnert.

person jfs    schedule 14.09.2014

Според тази статия има създадена непубликувана едноредова формула от Fliegel и Van Flandern за изчисляване на григорианска дата към юлианска дата:

JD = 367 * year - 7 * (year + (month + 9)/12)/4 - 3 * ((year + (month - 9)/7)/100 + 1)/4 + 275 * month/9 + day + 1721029

Това беше уплътнено от P. M. Muller и R. N. Wimberly от Jet Propulsion Laboratory, Пасадена, Калифорния за дати след март 1900 г. до:

JD = 367 * year - 7 * (year + (month + 9)/12)/4 + 275 * month/9 + day + 1721014

Тези формули са отклонени с 0,5, така че просто извадете 0,5 от формулите.

Използвайте известна манипулация на низове, за да извлечете действително данните и ще бъдете добри

>>> year, month, day = map(int,"2018.11.02".split("."))
>>> 367 * year - 7 * (year + (month + 9)/12)/4 + 275 * month/9 + day + 1721014 - 0.5
2458424.5
person FGol    schedule 13.07.2018

От горните примери, ето един ред (не-юлиански):

import datetime

doy = datetime.datetime.strptime('2014-01-01', '%Y-%m-%d').timetuple().tm_yday
person nvd    schedule 05.03.2015

Импортирам datetime lib и използвам strftime за извличане на „julian day“, година, месец, ден...

import datetime as dt
my_date = dt.datetime.strptime('2012.11.07', '%Y.%m.%d')
jld_str = my_date.strftime('%j') # '312'
jld_int = int(jld_str)           #  312
person Cícero Alves    schedule 10.03.2020