Bagaimana cara mengubah string waktu lokal ke UTC?

308

Bagaimana cara mengonversi string datetime di waktu lokal ke string di waktu UTC ?

Saya yakin saya pernah melakukan ini sebelumnya, tetapi tidak dapat menemukannya dan semoga SO akan membantu saya (dan yang lainnya) melakukannya di masa depan.

Klarifikasi : Misalnya, jika saya memiliki 2008-09-17 14:02:00di zona waktu lokal saya ( +10), saya ingin membuat string dengan UTCwaktu yang setara :2008-09-17 04:02:00 .

Juga, dari http://lucumr.pocoo.org/2011/7/15/eppur-si-muove/ , perhatikan bahwa secara umum ini tidak mungkin karena dengan DST dan masalah lain tidak ada konversi unik dari waktu setempat ke Waktu UTC.

Tom
sumber
1
Perlu diketahui bahwa metode mktime () membutuhkan "waktu lokal" sebagai input yang mungkin bukan yang Anda harapkan, saya menggunakannya dan itu mengacaukan segalanya. Silakan melirik tautan ini
Haifeng Zhang

Jawaban:

288

Pertama, parsing string ke objek datetime yang naif. Ini adalah contoh datetime.datetimetanpa informasi zona waktu yang terlampir. Lihat dokumentasi untukdatetime.strptime informasi tentang penguraian string tanggal.

Gunakan pytzmodul, yang dilengkapi dengan daftar zona waktu + UTC. Cari tahu apa zona waktu setempat, bangun objek zona waktu darinya, dan memanipulasi dan melampirkannya pada datetime yang naif.

Terakhir, gunakan datetime.astimezone()metode untuk mengonversi datetime ke UTC.

Kode sumber, menggunakan zona waktu lokal "America / Los_Angeles", untuk string "2001-2-3 10:11:12":

import pytz, datetime
local = pytz.timezone ("America/Los_Angeles")
naive = datetime.datetime.strptime ("2001-2-3 10:11:12", "%Y-%m-%d %H:%M:%S")
local_dt = local.localize(naive, is_dst=None)
utc_dt = local_dt.astimezone(pytz.utc)

Dari sana, Anda dapat menggunakan strftime()metode untuk memformat datetime UTC sesuai kebutuhan:

utc_dt.strftime ("%Y-%m-%d %H:%M:%S")
John Millikin
sumber
7
Harap edit jawaban Anda dengan kode berikut: [kode] local.lokasi (naif) [/ kode] Lihat dokumen: tautan Sayangnya menggunakan argumen tzinfo dari konstruktor datetime standar '' tidak berfungsi '' dengan pytz untuk banyak zona waktu. >>> datetime (2002, 10, 27, 12, 0, 0, tzinfo = amsterdam) .strftime (fmt) '2002-10-27 12:00:00 AMT + 0020'
Sam Stoelinga
2
Rupanya langkah "mencari tahu apa zona waktu setempat" terbukti lebih sulit daripada kedengarannya (praktis tidak mungkin).
Jason R. Coombs
2
Gunakan local.localize seperti yang disarankan oleh @SamStoelinga, atau Anda tidak akan memperhitungkan waktu penghematan siang hari.
Emil Stenström
Jawaban ini sangat membantu saya, tetapi saya ingin menunjukkan jebakan yang saya temui. Jika Anda memberikan waktu tetapi bukan tanggal, Anda mungkin mendapatkan hasil yang tidak terduga. Jadi pastikan Anda memberikan stempel waktu lengkap.
Steven Mercatante
145

Fungsi utcnow () modul datetime dapat digunakan untuk mendapatkan waktu UTC saat ini.

>>> import datetime
>>> utc_datetime = datetime.datetime.utcnow()
>>> utc_datetime.strftime("%Y-%m-%d %H:%M:%S")
'2010-02-01 06:59:19'

Seperti tautan yang disebutkan di atas oleh Tom: http://lucumr.pocoo.org/2011/7/15/eppur-si-muove/ mengatakan:

UTC adalah zona waktu tanpa waktu musim panas dan masih merupakan zona waktu tanpa perubahan konfigurasi di masa lalu.

Selalu ukur dan simpan waktu dalam UTC .

Jika Anda perlu merekam di mana waktu diambil, simpan secara terpisah. Jangan menyimpan waktu setempat + informasi zona waktu!

CATATAN - Jika ada data Anda di wilayah yang menggunakan DST, gunakanpytz dan lihat jawaban John Millikin.

Jika Anda ingin mendapatkan waktu UTC dari string yang diberikan dan keberuntungan Anda cukup untuk berada di wilayah di dunia yang tidak menggunakan DST, atau Anda memiliki data yang hanya offset dari UTC tanpa DST diterapkan:

-> menggunakan waktu lokal sebagai dasar untuk nilai offset:

>>> # Obtain the UTC Offset for the current system:
>>> UTC_OFFSET_TIMEDELTA = datetime.datetime.utcnow() - datetime.datetime.now()
>>> local_datetime = datetime.datetime.strptime("2008-09-17 14:04:00", "%Y-%m-%d %H:%M:%S")
>>> result_utc_datetime = local_datetime + UTC_OFFSET_TIMEDELTA
>>> result_utc_datetime.strftime("%Y-%m-%d %H:%M:%S")
'2008-09-17 04:04:00'

-> Atau, dari offset yang diketahui, menggunakan datetime.timedelta ():

>>> UTC_OFFSET = 10
>>> result_utc_datetime = local_datetime - datetime.timedelta(hours=UTC_OFFSET)
>>> result_utc_datetime.strftime("%Y-%m-%d %H:%M:%S")
'2008-09-17 04:04:00'

MEMPERBARUI:

Karena python 3.2 datetime.timezonetersedia. Anda dapat menghasilkan objek datetime sadar zona waktu dengan perintah di bawah ini:

import datetime

timezone_aware_dt = datetime.datetime.now(datetime.timezone.utc)

Jika Anda siap untuk mengambil konversi zona waktu baca ini:

https://medium.com/@eleroy/10-things-you-need-to-know-about-date-and-time-in-python-with-datetime-pytz-dateutil-timedelta-309bfbafb3f7

monkut
sumber
14
Itu hanya mengubah waktu saat ini, saya perlu mengambil waktu tertentu (sebagai string) dan mengkonversi ke UTC.
Tom
Saya tidak berpikir itu penting di sini, jika Anda menggunakan nilai offset standar. local_time = utc_time + utc_offset AND utc_time = local_time - utc_offset.
monkut
5
Ini hanya bekerja dengan waktu saat ini karena cap waktu yang lalu dan yang akan datang mungkin memiliki offset UTC yang berbeda karena DST.
Alex B
poin bagus ... jika Anda harus berurusan dengan DST Anda mungkin harus menggunakan pytz seperti yang disebutkan oleh John Millikin.
monkut
1
Ada delta sporadis antara panggilan ke utcnow () dan sekarang (). Itu baris kode berbahaya yang bisa menyebabkan kesalahan aneh nantinya tzinfo.utcoffset() must return a whole number of minutesdan seterusnya.
Pavel Vlasov
62

Terima kasih @rofly, konversi penuh dari string ke string adalah sebagai berikut:

time.strftime("%Y-%m-%d %H:%M:%S", 
              time.gmtime(time.mktime(time.strptime("2008-09-17 14:04:00", 
                                                    "%Y-%m-%d %H:%M:%S"))))

Ringkasan saya tentang time/ calendarfungsi:

time.strptime
string -> tuple (tidak ada zona waktu yang diterapkan, jadi cocok dengan string)

time.mktime
tuple waktu lokal -> detik sejak zaman (selalu waktu setempat)

time.gmtime
detik sejak zaman -> tuple dalam UTC

dan

calendar.timegm
tuple dalam UTC -> detik sejak zaman

time.localtime
detik sejak zaman -> tuple di zona waktu lokal

Tom
sumber
4
(always local time)tampaknya salah: input ke mktime () adalah waktu lokal, output adalah detik sejak zaman ( 1970-01-01 00:00:00 +0000 (UTC)) yang tidak tergantung pada zona waktu.
jfs
3
Juga ada kemungkinan 50% gagal selama transisi DST. Lihat Masalah dengan Localtime
jfs
38

Berikut ringkasan konversi waktu Python umum.

Beberapa metode menjatuhkan pecahan detik, dan ditandai dengan (s) . Formula eksplisit seperti ts = (d - epoch) / unitdapat digunakan sebagai gantinya (terima kasih jfs).

  • struct_time (UTC) → POSIX (s) :
    calendar.timegm(struct_time)
  • Dat naif (lokal) → POSIX (s) :
    calendar.timegm(stz.localize(dt, is_dst=None).utctimetuple())
    (pengecualian selama transisi DST, lihat komentar dari jfs)
  • Dat naif (UTC) → POSIX (s) :
    calendar.timegm(dt.utctimetuple())
  • Sadar datetime → POSIX (s) :
    calendar.timegm(dt.utctimetuple())
  • POSIX → struct_time (UTC, s ):
    time.gmtime(t)
    (lihat komentar dari jfs)
  • Waktu naif (lokal) → struct_time (UTC, s ):
    stz.localize(dt, is_dst=None).utctimetuple()
    (pengecualian selama transisi DST, lihat komentar dari jfs)
  • Waktu naif (UTC) → struct_time (UTC, s ):
    dt.utctimetuple()
  • Sadar datetime → struct_time (UTC, s ):
    dt.utctimetuple()
  • POSIX → Data naif (lokal):
    datetime.fromtimestamp(t, None)
    (mungkin gagal dalam kondisi tertentu, lihat komentar dari jfs di bawah)
  • struct_time (UTC) → Waktu naif (lokal, s ):
    datetime.datetime(struct_time[:6], tzinfo=UTC).astimezone(tz).replace(tzinfo=None)
    (tidak dapat mewakili detik kabisat, lihat komentar dari jfs)
  • Datad naif (UTC) → Datad naif (lokal):
    dt.replace(tzinfo=UTC).astimezone(tz).replace(tzinfo=None)
  • Sadar datetime → Naïve datetime (lokal):
    dt.astimezone(tz).replace(tzinfo=None)
  • POSIX → Naïve datetime (UTC):
    datetime.utcfromtimestamp(t)
  • struct_time (UTC) → Waktu naif (UTC, s ):
    datetime.datetime(*struct_time[:6])
    (tidak dapat mewakili detik kabisat, lihat komentar dari jfs)
  • Datad naif (lokal) → Datad naif (UTC):
    stz.localize(dt, is_dst=None).astimezone(UTC).replace(tzinfo=None)
    (pengecualian selama transisi DST, lihat komentar dari jfs)
  • Sadar datetime → Naïve datetime (UTC):
    dt.astimezone(UTC).replace(tzinfo=None)
  • POSIX → Sadar datetime:
    datetime.fromtimestamp(t, tz)
    (mungkin gagal untuk zona waktu non-pytz)
  • struct_time (UTC) → Sadar datetime (s) :
    datetime.datetime(struct_time[:6], tzinfo=UTC).astimezone(tz)
    (tidak bisa mewakili detik kabisat, lihat komentar dari jfs)
  • Datad naif (lokal) → Datad sadar:
    stz.localize(dt, is_dst=None)
    (pengecualian selama transisi DST, lihat komentar dari jfs)
  • Naïve datetime (UTC) → Sadar datetime:
    dt.replace(tzinfo=UTC)

Sumber: taaviburns.ca

akaihola
sumber
1
(1) fromtimestamp(t, None)mungkin gagal jika zona waktu lokal memiliki offset utc berbeda di t dan pustaka C tidak memiliki akses ke database tz pada platform yang diberikan. Anda dapat menggunakan tzlocal.get_localzone()untuk menyediakan tzdata dengan cara yang portabel. (2) fromtimestamp(t, tz)mungkin gagal untuk zona waktu non-pytz. (3) datetime(*struct_time[:6])Anda hilang *. (4) timegm(), utctimetuple(), struct_timesolusi berbasis menjatuhkan sepersekian detik. Anda bisa menggunakan rumus eksplisit seperti: sebagai ts = (d - epoch) / unitgantinya.
jfs
1
(5) stz.localize(dt, is_dst=None)menimbulkan pengecualian untuk waktu lokal yang ambigu atau tidak ada misalnya, selama transisi DST. Untuk menghindari pengecualian, gunakan stz.normalize(stz.localize(dt))yang dapat mengembalikan hasil yang tidak tepat. (6) datetime () tidak dapat mewakili lompatan kedua. Konversikan struct_timeke "detik sejak zaman" sebagai solusi pertama. (7) time.gmtime(t)tidak seperti calendar.timegm()dapat mengharapkan input non-POSIX jika zona waktu "benar" digunakan. Gunakan rumus eksplisit jika inputnya adalah POSIX:gmtime = lambda t: datetime(1970,1,1, tzinfo=utc) + timedelta(seconds=t)
jfs
Saya berharap ini ada di meja, lebih mudah dibaca (ada di tautan)
MichaelChirico
1
@MichaelChirico, jawaban ini menyatakan bahwa "Kami tidak (dan tidak akan) mengizinkan <table>tag. Maaf. Ini disengaja dan dirancang. Jika Anda memerlukan" tabel "yang cepat dan kotor, gunakan <pre>tata letak ASCII." Saya tidak percaya tabel ASCII akan lebih mudah dibaca daripada daftar di atas.
akaihola
nah itu disayangkan. Anda tetap memiliki upvote saya ... mungkin merujuk tabel di tautan dalam jawaban Anda?
MichaelChirico
25
def local_to_utc(t):
    secs = time.mktime(t)
    return time.gmtime(secs)

def utc_to_local(t):
    secs = calendar.timegm(t)
    return time.localtime(secs)

Sumber: http://feihonghsu.blogspot.com/2008/02/converting-from-local-time-to-utc.html

Contoh penggunaan dari bd808 : Jika sumber Anda adalah datetime.datetimeobjek t, panggil sebagai:

local_to_utc(t.timetuple())
Chuck Callebs
sumber
5
Jika sumber Anda adalah objek datetime.datetime t, panggil sebagai: local_to_utc (t.timetuple ())
bd808
2
.timetuple()set panggilan tm_isdstke -1; ada kemungkinan 50% mktime()gagal selama transisi DST.
jfs
1
Solusi oleh Chuck kehilangan informasi milidetik.
Luca
21

Saya beruntung dengan dateutil (yang direkomendasikan secara luas di SO untuk pertanyaan terkait lainnya):

from datetime import *
from dateutil import *
from dateutil.tz import *

# METHOD 1: Hardcode zones:
utc_zone = tz.gettz('UTC')
local_zone = tz.gettz('America/Chicago')
# METHOD 2: Auto-detect zones:
utc_zone = tz.tzutc()
local_zone = tz.tzlocal()

# Convert time string to datetime
local_time = datetime.strptime("2008-09-17 14:02:00", '%Y-%m-%d %H:%M:%S')

# Tell the datetime object that it's in local time zone since 
# datetime objects are 'naive' by default
local_time = local_time.replace(tzinfo=local_zone)
# Convert time to UTC
utc_time = local_time.astimezone(utc_zone)
# Generate UTC time string
utc_string = utc_time.strftime('%Y-%m-%d %H:%M:%S')

(Kode diturunkan dari jawaban ini untuk Mengonversi string datetime UTC ke datetime lokal )

Yarin
sumber
dateutildapat gagal untuk tanggal yang lalu jika zona waktu lokal memiliki offset utc yang berbeda maka (tidak terkait dengan transisi DST) pada sistem di mana implementasinya tidak menggunakan database zona waktu historis (terutama Windows). pytz+tzlocal bisa digunakan sebagai gantinya.
jfs
@ JFSebastian- Belum pernah mendengar itu- di mana kita bisa mendapatkan info lebih lanjut?
Yarin
ambil mesin Windows, atur zona waktu yang memiliki offset utc berbeda di masa lalu mis., Eropa / Moskow. Bandingkan hasil dengan pytz . Plus, Anda dapat menguji bug ini yang gagal bahkan di Ubuntu meskipun saya tidak yakin tentang penggunaan API yang benar dalam kasus ini.
jfs
Apa hasilnya? Silakan kirim hasilnya.
not2qubit
18

Satu lagi contoh dengan pytz, tetapi termasuk localize (), yang menyelamatkan hari saya.

import pytz, datetime
utc = pytz.utc
fmt = '%Y-%m-%d %H:%M:%S'
amsterdam = pytz.timezone('Europe/Amsterdam')

dt = datetime.datetime.strptime("2012-04-06 10:00:00", fmt)
am_dt = amsterdam.localize(dt)
print am_dt.astimezone(utc).strftime(fmt)
'2012-04-06 08:00:00'
Paulius Sladkevičius
sumber
12

Saya sudah paling sukses dengan python-dateutil :

from dateutil import tz

def datetime_to_utc(date):
    """Returns date in UTC w/o tzinfo"""
    return date.astimezone(tz.gettz('UTC')).replace(tzinfo=None) if date.tzinfo else date
Shu Wu
sumber
7
import time

import datetime

def Local2UTC(LocalTime):

    EpochSecond = time.mktime(LocalTime.timetuple())
    utcTime = datetime.datetime.utcfromtimestamp(EpochSecond)

    return utcTime

>>> LocalTime = datetime.datetime.now()

>>> UTCTime = Local2UTC(LocalTime)

>>> LocalTime.ctime()

'Thu Feb  3 22:33:46 2011'

>>> UTCTime.ctime()

'Fri Feb  4 05:33:46 2011'
Scipythonee
sumber
mktime(dt.timetuple())dapat gagal selama transisi DST . Ada LocalTimezonedalam dokumen (ini berfungsi untuk definisi zona waktu terbaru tetapi dapat gagal untuk tanggal yang lalu (tidak terkait dengan DST))
jfs
5

jika Anda lebih suka datetime. waktu:

dt = datetime.strptime("2008-09-17 14:04:00","%Y-%m-%d %H:%M:%S")
utc_struct_time = time.gmtime(time.mktime(dt.timetuple()))
utc_dt = datetime.fromtimestamp(time.mktime(utc_struct_time))
print dt.strftime("%Y-%m-%d %H:%M:%S")
pengguna235042
sumber
1
Tentu, tapi saya tidak mengerti mengapa Anda lebih suka itu. Dibutuhkan impor tambahan dan 3 panggilan fungsi lebih banyak dari versi saya ...
Tom
% Z dan% z masih mencetak spasi putih.
Pavel Vlasov
2
itu tidak benar. Gagal jika zona waktu lokal bukan UTC. mktime()mengharapkan waktu lokal sebagai input. fromtimestamp()mengembalikan waktu setempat, bukan utc. Jika Anda memperbaikinya maka lihat masalahdateutil
jfs
5

Sederhana

Saya melakukannya seperti ini:

>>> utc_delta = datetime.utcnow()-datetime.now()
>>> utc_time = datetime(2008, 9, 17, 14, 2, 0) + utc_delta
>>> print(utc_time)
2008-09-17 19:01:59.999996

Implementasi yang Mewah

Jika Anda ingin menjadi mewah, Anda dapat mengubahnya menjadi functor:

class to_utc():
    utc_delta = datetime.utcnow() - datetime.now()

    def __call__(cls, t):
        return t + cls.utc_delta

Hasil:

>>> utc_converter = to_utc()
>>> print(utc_converter(datetime(2008, 9, 17, 14, 2, 0)))
2008-09-17 19:01:59.999996
uclatommy
sumber
5
ini tidak berfungsi untuk menghemat waktu siang hari - mis. jika saat ini musim panas dan tanggal Anda mengonversi ada di musim dingin. dan pertanyaannya adalah tentang mengubah tanggal yang disimpan sebagai string ...
Tom
1
FYI. Masalah terbesar dengan metode ini (selain penghematan siang hari) adalah beberapa milidetik dimana delta akan dimatikan. Semua undangan kalender saya muncul sebagai mati 1 menit.
Nostalg.io
4

Anda dapat melakukannya dengan:

>>> from time import strftime, gmtime, localtime
>>> strftime('%H:%M:%S', gmtime()) #UTC time
>>> strftime('%H:%M:%S', localtime()) # localtime
Cristian Salamea
sumber
3

Bagaimana tentang -

time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(seconds))

jika detik Nonemaka itu mengubah waktu setempat ke UTC waktu lain mengkonversi waktu yang lewat ke UTC.

Tom
sumber
2

Untuk menghemat waktu siang hari, dll.

Tidak ada jawaban di atas yang membantu saya. Kode di bawah ini berfungsi untuk GMT.

def get_utc_from_local(date_time, local_tz=None):
    assert date_time.__class__.__name__ == 'datetime'
    if local_tz is None:
        local_tz = pytz.timezone(settings.TIME_ZONE) # Django eg, "Europe/London"
    local_time = local_tz.normalize(local_tz.localize(date_time))
    return local_time.astimezone(pytz.utc)

import pytz
from datetime import datetime

summer_11_am = datetime(2011, 7, 1, 11)
get_utc_from_local(summer_11_am)
>>>datetime.datetime(2011, 7, 1, 10, 0, tzinfo=<UTC>)

winter_11_am = datetime(2011, 11, 11, 11)
get_utc_from_local(winter_11_am)
>>>datetime.datetime(2011, 11, 11, 11, 0, tzinfo=<UTC>)
Dantalion
sumber
2

Menggunakan http://crsmithdev.com/arrow/

arrowObj = arrow.Arrow.strptime('2017-02-20 10:00:00', '%Y-%m-%d %H:%M:%S' , 'US/Eastern')

arrowObj.to('UTC') or arrowObj.to('local') 

Perpustakaan ini memudahkan hidup :)

Yash
sumber
arrow is awesome: arrow.get (datetime.now (), 'local'). to ('utc'). naif
SteveJ
1

Saya menemukan jawaban terbaik untuk pertanyaan lain di sini . Ini hanya menggunakan python built-in libraries dan tidak mengharuskan Anda untuk memasukkan zona waktu lokal Anda (persyaratan dalam kasus saya)

import time
import calendar

local_time = time.strptime("2018-12-13T09:32:00.000", "%Y-%m-%dT%H:%M:%S.%f")
local_seconds = time.mktime(local_time)
utc_time = time.gmtime(local_seconds)

Saya memposting ulang jawabannya di sini karena pertanyaan ini muncul di google alih-alih pertanyaan yang ditautkan tergantung pada kata kunci pencarian.

franksands
sumber
1

Saya memiliki kode ini di salah satu proyek saya:

from datetime import datetime
## datetime.timezone works in newer versions of python
try:
    from datetime import timezone
    utc_tz = timezone.utc
except:
    import pytz
    utc_tz = pytz.utc

def _to_utc_date_string(ts):
    # type (Union[date,datetime]]) -> str
    """coerce datetimes to UTC (assume localtime if nothing is given)"""
    if (isinstance(ts, datetime)):
        try:
            ## in python 3.6 and higher, ts.astimezone() will assume a
            ## naive timestamp is localtime (and so do we)
            ts = ts.astimezone(utc_tz)
        except:
            ## in python 2.7 and 3.5, ts.astimezone() will fail on
            ## naive timestamps, but we'd like to assume they are
            ## localtime
            import tzlocal
            ts = tzlocal.get_localzone().localize(ts).astimezone(utc_tz)
    return ts.strftime("%Y%m%dT%H%M%SZ")
tobixen
sumber
0

Dalam python3:

pip install python-dateutil

from dateutil.parser import tz

mydt.astimezone(tz.gettz('UTC')).replace(tzinfo=None) 
spedy
sumber
ini tampaknya tidak berhasil, itu menimbulkan pengecualian ValueError: ValueError: astimezone () tidak dapat diterapkan pada waktu yang naif
Stormsson
Seharusnya: from dateutil import tz
Javier
-3

Bagaimana tentang -

time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(seconds))

jika detik Nonemaka itu mengubah waktu setempat ke UTC waktu lain mengkonversi waktu yang lewat ke UTC.

Mohammad Efazati
sumber
1
Ini tidak membantu, pertanyaannya adalah mengubah string waktu lokal yang diberikan ke string utc.
Tom