Ασχολούμαι με ημερομηνίες στην Python και πρέπει να τις μετατρέψω σε UTC timestamps για να χρησιμοποιηθούν μέσα σε Javascript. Ο παρακάτω κώδικας δεν λειτουργεί:
>>> d = datetime.date(2011,01,01)
>>> datetime.datetime.utcfromtimestamp(time.mktime(d.timetuple()))
datetime.datetime(2010, 12, 31, 23, 0)
Η μετατροπή του αντικειμένου ημερομηνίας πρώτα σε datetime επίσης δεν βοηθάει. Δοκίμασα το παράδειγμα σε αυτό το link από, αλλά:
from pytz import utc, timezone
from datetime import datetime
from time import mktime
input_date = datetime(year=2011, month=1, day=15)
και τώρα είτε:
mktime(utc.localize(input_date).utctimetuple())
είτε
mktime(timezone('US/Eastern').localize(input_date).utctimetuple())
λειτουργεί.
Οπότε γενική ερώτηση: πώς μπορώ να πάρω μια ημερομηνία που μετατρέπεται σε δευτερόλεπτα από την εποχή σύμφωνα με την UTC;
Εάν d = date(2011, 1, 1, 1)
είναι σε UTC:
>>> from datetime import datetime, date
>>> import calendar
>>> timestamp1 = calendar.timegm(d.timetuple())
>>> datetime.utcfromtimestamp(timestamp1)
datetime.datetime(2011, 1, 1, 0, 0)
Αν d
είναι σε τοπική ζώνη ώρας:
>>> import time
>>> timestamp2 = time.mktime(d.timetuple()) # DO NOT USE IT WITH UTC DATE
>>> datetime.fromtimestamp(timestamp2)
datetime.datetime(2011, 1, 1, 0, 0)
Τα timestamp1
και timestamp2
μπορεί να διαφέρουν εάν τα μεσάνυχτα στην τοπική ζώνη ώρας δεν είναι η ίδια χρονική στιγμή με τα μεσάνυχτα στην UTC.
Η mktime()
μπορεί να επιστρέψει λανθασμένο αποτέλεσμα αν το d
αντιστοιχεί σε διφορούμενη τοπική ώρα (π.χ. κατά τη διάρκεια της μετάβασης στη θερινή ώρα) ή αν το d
είναι μια παρελθούσα (μελλοντική) ημερομηνία, όταν η μετατόπιση utc μπορεί να ήταν διαφορετική και η C mktime()
δεν έχει πρόσβαση στη βάση δεδομένων tz στη δεδομένη πλατφόρμα. Θα μπορούσατε να χρησιμοποιήσετε την ενότητα pytz
(π.χ. μέσω της tzlocal.get_localzone()
) για να αποκτήσετε πρόσβαση στη βάση δεδομένων tz σε όλες τις πλατφόρμες. Επίσης, η utcfromtimestamp()
μπορεί να αποτύχει και η mktime()
μπορεί να επιστρέψει μη-POSIX timestamp αν χρησιμοποιείται "right"
timezone.
Για να μετατρέψετε το αντικείμενο datetime.date
που αντιπροσωπεύει την ημερομηνία σε UTC χωρίς την calendar.timegm()
:
DAY = 24*60*60 # POSIX day in seconds (exact value)
timestamp = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * DAY
timestamp = (utc_date - date(1970, 1, 1)).days * DAY
Για να μετατρέψετε το αντικείμενο datetime.datetime
(όχι datetime.date
) που αντιπροσωπεύει ήδη την ώρα σε UTC στο αντίστοιχο POSIX timestamp (ένα float
).
from datetime import timezone
timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
Σημείωση: Είναι απαραίτητο να δώσετε ρητά την timezone.utc
, διαφορετικά η .timestamp()
υποθέτει ότι το αφελές datetime αντικείμενό σας είναι σε τοπική ζώνη ώρας.
Από τα έγγραφα για την datetime.utcfromtimestamp()
:
Δεν υπάρχει μέθοδος για να λάβετε το timestamp από ένα datetime instance, αλλά η χρονοσφραγίδα POSIX που αντιστοιχεί σε μια περίπτωση datetime dt μπορεί να είναι εύκολα να υπολογιστεί ως εξής. Για ένα αφελές dt:
timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)
Και για ένα συνειδητό dt:
timestamp = (dt - datetime(1970,1,1, tzinfo=timezone.utc)) / timedelta(seconds=1)
Ενδιαφέρουσα ανάγνωση: (http://www.ucolick.org/~sla/leapsecs/epochtime.html) σχετικά με τη διαφορά μεταξύ Τι ώρα είναι; και Πόσα δευτερόλεπτα έχουν περάσει;
Βλέπε επίσης: datetime needs an "epoch" method
Για να προσαρμόσετε τον παραπάνω κώδικα για την Python 2:
timestamp = (dt - datetime(1970, 1, 1)).total_seconds()
όπου timedelta.total_seconds()
ισοδυναμεί με (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
που υπολογίζεται με ενεργοποιημένη την πραγματική διαίρεση.
from __future__ import division
from datetime import datetime, timedelta
def totimestamp(dt, epoch=datetime(1970,1,1)):
td = dt - epoch
# return td.total_seconds()
return (td.microseconds + (td.seconds + td.days * 86400) * 10**6) / 10**6
now = datetime.utcnow()
print now
print totimestamp(now)
Προσοχή στα θέματα κινητής υποδιαστολής.
2012-01-08 15:34:10.022403
1326036850.02
datetime
σε POSIX timestampassert dt.tzinfo is not None and dt.utcoffset() is not None
timestamp = dt.timestamp() # Python 3.3+
Στην Python 3:
from datetime import datetime, timedelta, timezone
epoch = datetime(1970, 1, 1, tzinfo=timezone.utc)
timestamp = (dt - epoch) / timedelta(seconds=1)
integer_timestamp = (dt - epoch) // timedelta(seconds=1)
Στην Python 2:
# utc time = local time - utc offset
utc_naive = dt.replace(tzinfo=None) - dt.utcoffset()
timestamp = (utc_naive - datetime(1970, 1, 1)).total_seconds()
Υπόθεση 1: Προσπαθείτε να μετατρέψετε μια ημερομηνία σε χρονοσφραγίδα, ωστόσο, δεδομένου ότι μια ημερομηνία καλύπτει μια περίοδο 24 ωρών, δεν υπάρχει μια μοναδική χρονοσφραγίδα που να αντιπροσωπεύει αυτή την ημερομηνία. Θα υποθέσω ότι θέλετε να αναπαραστήσετε τη χρονοσφραγίδα αυτής της ημερομηνίας τα μεσάνυχτα (00:00:00.000).
Υπόθεση 2: Η ημερομηνία που παρουσιάζετε δεν συνδέεται με μια συγκεκριμένη χρονική ζώνη, ωστόσο θέλετε να προσδιορίσετε τη μετατόπιση από μια συγκεκριμένη χρονική ζώνη (UTC). Χωρίς να γνωρίζετε τη χρονική ζώνη στην οποία βρίσκεται η ημερομηνία, δεν είναι δυνατόν να υπολογίσετε μια χρονοσφραγίδα για μια συγκεκριμένη χρονική ζώνη. Θα υποθέσω ότι θέλετε να αντιμετωπίσετε την ημερομηνία σαν να βρίσκεται στη ζώνη ώρας του τοπικού συστήματος.
Πρώτον, μπορείτε να μετατρέψετε την περίπτωση ημερομηνίας σε μια πλειάδα που αντιπροσωπεύει τα διάφορα στοιχεία της ώρας χρησιμοποιώντας το μέλος timetuple()
:
dtt = d.timetuple() # time.struct_time(tm_year=2011, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=5, tm_yday=1, tm_isdst=-1)
Στη συνέχεια, μπορείτε να τη μετατρέψετε σε χρονοσήμανση χρησιμοποιώντας το time.mktime
:
ts = time.mktime(dtt) # 1293868800.0
Μπορείτε να επαληθεύσετε αυτή τη μέθοδο δοκιμάζοντάς την με την ίδια την ώρα της εποχής (1970-01-01), οπότε η συνάρτηση θα πρέπει να επιστρέφει τη χρονική μετατόπιση για την τοπική ζώνη ώρας κατά την ημερομηνία αυτή:
d = datetime.date(1970,1,1)
dtt = d.timetuple() # time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=-1)
ts = time.mktime(dtt) # 28800.0
28800.0
είναι 8 ώρες, το οποίο θα ήταν σωστό για τη ζώνη ώρας του Ειρηνικού (όπου βρίσκομαι εγώ).
Μια πλήρης χρονοσειρά περιέχει:
[+HHMM ή -HHMM]
Για παράδειγμα:
1970-01-01 06:00:00 +0500
== 1970-01-01-01 01:00:00 +0000
== UNIX timestamp:3600
$ python3
>>> from datetime import datetime
>>> from calendar import timegm
>>> tm = '1970-01-01 06:00:00 +0500'
>>> fmt = '%Y-%m-%d %H:%M:%S %z'
>>> timegm(datetime.strptime(tm, fmt).utctimetuple())
3600
Σημείωση:
`
UNIX timestamp
είναι ένας αριθμός κινητής υποδιαστολής εκφρασμένος σε δευτερόλεπτα από την εποχή, σε UTC.
Επεξεργασία:
$ python3
>>> from datetime import datetime, timezone, timedelta
>>> from calendar import timegm
>>> dt = datetime(1970, 1, 1, 6, 0)
>>> tz = timezone(timedelta(hours=5))
>>> timegm(dt.replace(tzinfo=tz).utctimetuple())
3600