Python Datetime Modülü İle Tarih - Zaman İşlemleri
Datetime Paketi Kullanımı
Python ile çalışırken sıklıkla bu işlemin ve/veya paketin R ya da JS karşılığı nedir gibi sorular sorarak ilerliyorum. Bu konuda birkaç yazı daha yayınlayacağım. Bu karşılaştırmanın temel nedeni hem hafızamı taze tutarak pratik yapmak hem de farklı çözüm yöntemlerine açık olmak istemem. Bu yazıda da kısmen bu konuya ve Python programlama dilinin ön tanımlı olarak sunduğu datetime
modülüne değinmeye çalışacağım.
R programlama dili as.Date
fonksiyonu ile temel bir şekilde tarih veri tipi ile ilgili işlemler yapılabilmesini mümkün kılmakta1. Ancak, zaman dilimleri ve biçimler arasında geçişlerde bu fonksiyon maalesef yeterli olmayabiliyor. Bu gibi durumlarda, tidyverse koleksiyonunun bir parçası olan lubridate paketi ile pratik bir şekilde tarih ve saat verileri yönetilebiliyor2. JavaScript/NodeJS tarafında ise hatırlayabildiğim sadece datetime modülü oldu3.
Python tarafında ise öne çıkan modül ön tanımlı olarak yine datetime adı ile sunuluyor. Bunun yanı sıra, kullanılabilecek başka ne gibi paketler olduğunu da merak ederek kısa bir araştırma yaptım ve Python için yazının son bölümünde datetime modülüne alernatif olabilecek birkaç pakete yer verdim.
Datetime Modülü
Python veri tipleri arasında tarih-zaman tipi yer almamakta. Ancak, datetime
modülü ile metin dizileri ve tarih-zaman biçimleri arasında işlemler yürütülebilmekte. Python İle Basit Twitter API İşlemleri başlıklı yazıda yer alan örnek üzerine çalışırken, tarih işlemlerinde hem datetime
modülü dokümantasyonunu inceleme ve sunulan metodlarla ilgili örnek işlemler gerçekleştirme imkanım oldu. Bu yazıda da aldığım kısa notları paylaşmak ve basit birkaç örneğe yer vermek istiyorum4 5.
İlgili yazıdaki tarih işlemi şu şekildeydi:
currentTime = datetime.datetime.today().strftime('%Y-%m-%d') # '2021-07-31'
previousTime = (datetime.datetime.today() - datetime.timedelta(days=7)).strftime('%Y-%m-%d') # '2021-07-24'
datetime
modülünü import datetime
ile çalışmalara dahil edebiliriz. Ancak, modül bünyesinde date
, time
ve datetime
sınıflarını barındırdığı için sadece ilgili sınıf da çağırılabilir.
from datetime import datetime # datetime.now()
# import datetime # datetime.datetime.now()
# dir(datetime.datetime)
# ['__add__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__radd__', '__reduce__', '__reduce_ex__', '__repr__', '__rsub__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', 'astimezone', 'combine', 'ctime', 'date', 'day', 'dst', 'fold', 'fromisoformat', 'fromordinal', 'fromtimestamp', 'hour', 'isocalendar', 'isoformat', 'isoweekday', 'max', 'microsecond', 'min', 'minute', 'month', 'now', 'replace', 'resolution', 'second', 'strftime', 'strptime', 'time', 'timestamp', 'timetuple', 'timetz', 'today', 'toordinal', 'tzinfo', 'tzname', 'utcfromtimestamp', 'utcnow', 'utcoffset', 'utctimetuple', 'weekday', 'year']
date
sınıfı tarihler ile ilgili işlemler yapılabilmesini sağlarken, time
zaman ile ilgili işlemleri barındırır. datetime
ise date
ve time
sınıflarını kapsar.
NOW ve TODAY
now()
ve today()
metodları bize anlık olarak yıl, ay, gün, saat, dakika, saniye ve mikrosaniye bilgilerini verir. Bu zaman bilgilerini ayrı ayrı çağırmak da mümkün.
datetime.datetime.today() # datetime.datetime(2021, 7, 31, 19, 31, 46, 197762)
datetime.datetime.now().year # 2021
datetime.datetime.now().month # 7
datetime.datetime.now().day # 31
datetime.datetime.now().hour # 19
datetime.datetime.now().minute # 31
datetime.datetime.now().second # 46
datetime.datetime.now().microsecond # 197762
STRFTIME ve STRPTIME
strftime()
metodu direktifler aracılığı ile tarih ve saat formatlarını yönetebilmemizi ve bu işlem sonucunda tarih nesnesinin bir karakter dizisine dönüştürülmesini sağlar.
datetime.datetime.now().strftime(format='%Y') # 2021
datetime.datetime.now().strftime(format='%m/%d/%y') # 07/31/21
datetime.datetime.now().strftime(format='%x') # 07/31/21
datetime.datetime.now().strftime(format='%d.%m.%Y') # 31.07.2021
strptime()
metodu ise yine tarih ve saat formatlarını kullanarak bir karakter dizisini tarih nesnesine dönüştürebilmemizi mümkün kılar.
datetime.datetime.strptime('31 July 2014 12:34:44', '%d %B %Y %H:%M:%S') # datetime.datetime(2014, 7, 31, 12, 34, 44)
datetime.datetime.strptime('07/31/21', '%m/%d/%y') # datetime.datetime(2021, 7, 31, 0, 0)
datetime.datetime.strptime('07/31/21', '%x') # datetime.datetime(2021, 7, 31, 0, 0)
Bir başka örnekte de farklı seperatörlere sahip tarihsel ifadeleri tarih formatına dönüştürelim. Bu aşamada ek olarak regex işlemleri yapmamızı sağlayan re
paketini de örneğe dahil edeceğim.
import re
dates = [datetime.datetime.strptime(re.sub('[^0-9]', '/', d), '%m/%d/%Y') for d in ['11-23-2021', '05/06/1991', '10 10 2000']]
print(dates)
Öne Çıkan Direktifler
Aşağıda sıklıkla kullanılan bazı direktifleri tablo halinde görebilirsiniz6 7.
Direktif | Anlamı | Örnek |
---|---|---|
%X | Lokal olarak uyarlanmış zaman | 21:30:00 (en_US) |
%x | Lokal olarak uyarlanmış tarih | 08/16/1988 (en_US) |
%Y | 4 haneli yıl | 2021, 1990, vb. |
%y | 2 haneli yıl | 21,90, vb. |
%m | Sayısal olarak ay | 01, 10, 12 |
%B | Lokal olarak uyarlanmış ay | July, Temmuz, vb. |
%b | Lokal olarak uyarlanmış, kısaltılmış ay | Jul, Tem, vb. |
%A | Lokal olarak uyarlanmış günün adı | Monday, Pazartesi, vb. |
%a | Lokal olarak uyarlanmış, kısaltılmış günün adı | Mon, Pzt, vb. |
%w | Sayısal olarak haftanın günü | 0 (Pazar), 3, 6, vb. |
%d | Sayısal olarak ayın günü | 01, 22, 31, vb. |
%H | 24 saalik zaman gösterimi | 00, 11, 23, vb. |
%I | 12 saatlik zaman gösterimi | 01, 10, 24, vb. |
%p | Lokal olarak uyarlanmış gün periyodu | AM, ÖÖ, PM, ÖS |
%M | Dakika | 00,33,59 |
%S | Saniye | 00, 33, 59 |
%Z | Zaman dilimi | UTC, EST, GMT, vb. |
%z | Sayısal formatta zaman dilimi | +0000, -0400, vb. |
Lokal tanımları sisteme göre değişiklik gösterebilir. Seçilebilir tanımları görmek için komut satırında locale -a
komutunu uygulayabilirsiniz. Bu komut gibi bir çıktı döndürecektir.
C
C.UTF-8
en_US.utf8
tr_TR
POSIX
Lokal bilgisini ayrıca Python modülü olan locale
ile de görüntülemek mümkün8.
import locale
print(locale.getlocale()) # ('en_US', 'UTF-8')
locale -a
ile listelenen seçenekler arasından birini seçmek için setlocale()
metodunu kullanabiliriz.
locale.setlocale(locale.LC_ALL, 'en_US')
datetime.datetime.now().strftime(format='%b') # Aug
datetime.datetime.now().strftime(format='%x') # 07/31/2021
locale.setlocale(locale.LC_ALL, 'tr_TR')
datetime.datetime.now().strftime(format='%b') # Ağu
datetime.datetime.now().strftime(format='%x') # 31/07/2021
CTIME
ctime()
metodu belirtilen tarih ve zamanı okunaklı bir karakter dizisi verir.
datetime.datetime.today().ctime() # Sat Jul 31 21:21:24 2021
datetime.datetime(2021, 7, 1).ctime() # Thu Jul 1 00:00:00 2021
(datetime.datetime.today() - datetime.timedelta(days=217)).ctime() # Sat Dec 26 21:24:04 2020
datetime.datetime.ctime(datetime.datetime.now()) # Sun Aug 1 07:21:55 2021
TIMESTAMP ve FROMTIMESTAMP
Dosya/dizin işlemlerinde oluşturma ve son değişiklik tarihleri gibi değerleri zaman etiketi (timestamp) biçiminde görüntüleriz.
os.stat('Image.png').st_mtime #1627801430.7354434
timestamp()
metodu tarih ve zaman değerlerini zaman etiketi biçimine dönüştürebilmemizi sağlar.
datetime.datetime.today().timestamp() # 1627802786.984535
(datetime.datetime.today() - datetime.timedelta(days=217)).timestamp() # 1609054148.42208
datetime.datetime.fromtimestamp(datetime.datetime.timestamp(datetime.datetime.now())) # datetime.datetime(2021, 8, 1, 7, 33, 7, 576549)
fromtimestamp()
metodu ise zaman etiketinin insan tarafından okunabilir (human readable) biçime dönüştürülmesini sağlar.
datetime.datetime.fromtimestamp(1627802786.984535) # datetime.datetime(2021, 8, 1, 7, 26, 26, 984535)
Diğer İşlemler
Zaman işlemlerinde kullanılabilecek diğer konulara da kısaca değinelim.
ISOFORMAT ve FROMISOFORMAT
isoformat()
metodu tarih-zaman değerini ISO formatında edinebilmemizi sağlar.
datetime.datetime.utcfromtimestamp(1627804283.441646).isoformat() # 2021-08-01T07:51:23.441646
fromisoformat()
metodu ISO formatındaki tarihsel ifadeyi datetime nesnesine dönüştürür.
datetime.fromisoformat('2021-08-01T00:05:23') # datetime.datetime(2021, 8, 1, 0, 5, 23)
TIMEDELTA
Timedelta nesnesi, bir süreyi, iki tarih veya saat arasındaki farkı temsil eder, bu sayede karşılaştırmalar ve matematiksel işlemler yapılabilir9.
datetime.datetime.today() - datetime.timedelta(days=7) # datetime.datetime(2021, 7, 25, 8, 2, 45, 800333)
datetime.datetime.today() + datetime.timedelta(days=-127) # datetime.datetime(2021, 3, 27, 8, 16, 3, 744547)
(datetime.datetime.today() - datetime.timedelta(days=50, hours=8, seconds=27, microseconds=10, minutes=5)).isoformat() # 2021-06-11T23:59:19.479398
REPLACE
datetime.datetime(2002, 12, 31).replace(day=15) # datetime.datetime(2002, 12, 15, 0, 0)
datetime.datetime(2021, 5, 10).replace(year=1995, month=11, day=15).isocalendar() # (1995, 46, 3)
DİĞER MODÜLLER
PANDAS
Pandas datetime
ve timedelta
veri tiplarini kullanılabilir olarak sunar. Bu sayede, ön tanımlı datetime
modülünün yanı sıra, Pandas kapsamında sunulan datetime
ve timedelta
nesneleri ile de kolaylıkla tarihsel-zamansal işlemler yapabilmek mümkün hale gelmektedir10 11.
import pandas as pd
pd.to_datetime("1th of Aug, 2021") # Timestamp('2021-08-01 00:00:00')
df = pd.DataFrame(['2021-10-05', '2019-05-06', '2015-03-11'], columns=['Dates'])
[(pd.Timestamp(dt) + pd.Timedelta('-15 day')).day_name() for dt in df['Dates']] # ['Monday', 'Sunday', 'Tuesday']
pd.Timedelta("1 days 2 hours") # Timedelta('1 days 02:00:00')
pd.Timedelta(pd.offsets.Day(2)) # Timedelta('2 days 00:00:00')
pd.Series(pd.date_range("2012-1-1", periods=3, freq="D"))
'''
0 2012-01-01
1 2012-01-02
2 2012-01-03
dtype: datetime64[ns]
'''
pd.date_range("2018-01-01", periods=3, freq="H")
'''
DatetimeIndex(['2018-01-01 00:00:00', '2018-01-01 01:00:00', '2018-01-01 02:00:00'],
dtype='datetime64[ns]', freq='H')
'''
pd.date_range(start='1/1/2018', end='1/08/2018')
'''
DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',
'2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08'],
dtype='datetime64[ns]', freq='D')
'''
pd.date_range(start='1/1/2018', periods=5, freq='M')
'''
DatetimeIndex(['2018-01-31', '2018-02-28', '2018-03-31', '2018-04-30',
'2018-05-31'],
dtype='datetime64[ns]', freq='M')
'''
df = pd.DataFrame({'Dates': ['2021-10-05', '2021-10-06', '2021-10-04','2021-11-15', '2021-11-21', '2021-11-09'], 'Counts': [20,23,41,55,32,24]})
df['Dates'] = pd.to_datetime(df['Dates'])
df.resample('M', on='Dates')['Counts'].mean()
'''
Dates
2021-10-31 28.0
2021-11-30 37.0
Freq: M, Name: Counts, dtype: float64
'''
df['Counts'].groupby(df['Dates'].dt.month).mean()
'''
Dates
10 28.0
11 37.0
Name: Counts, dtype: float64
'''
DATEUTIL
dateutil
datetime
'in daha pratik ve geliştirilmiş versiyonu olarak değerlendirilebilir12.
from datetime import *; from dateutil.relativedelta import *
import calendar
NOW = datetime.now()
TODAY = date.today()
print(NOW) # 2021-08-01 08:43:27.891459
print(TODAY) # 2021-08-01
NOW+relativedelta(months=+1) # datetime.datetime(2021, 9, 1, 8, 45, 51, 522361)
ARROW
Python için geliştirilen Arrow'un, R programlama dili için geliştirilen lubridate paketine en aykın seçenek olduğunu düşünüyorum13. Özellikle zaman dilimleri ilgili metodlar sayeside oldukça kolay bir şekilde yönetilebilmekte.
import arrow
arrow.utcnow() # <Arrow [2021-08-01T08:49:17.631022+00:00]>
arrow.utcnow().shift(hours=-1) # <Arrow [2021-08-01T07:50:21.604033+00:00]>
arrow.utcnow().to('GMT+3') # <Arrow [2021-08-01T11:53:15.176165+03:00]>
arrow.utcnow().to('GMT-3').shift(hours=-1) # <Arrow [2021-08-01T10:54:03.573688+03:00]>
arrow.utcnow().to('EST').shift(hours=2).humanize() # in 2 hours
SIMPLEDATE
Simpledate paketi zaman dilimi ve formatlar gibi biçimler arasında dönüştürme başta olmak üzere çeşitli kolaylaştırıcı metodlar sunar14.
!pip install pytz tzlocal simple-date
import simpledate
simpledate.SimpleDate(tz='America/New_York') # SimpleDate('2021-08-01 05:19:47.150963 EDT', tz='America/New_York')
simpledate.SimpleDate(tz=120, format='%Y-%m-%d %z') # SimpleDate('2021-08-01 +0200', tz='pytz.FixedOffset(120)')
simpledate.SimpleDate('2013-01-01', tz='EST', country='US') # SimpleDate('2013-01-01')
simpledate.SimpleDate('6/12/2013', format='%m/%d/%Y') # SimpleDate('06/12/2013', tz='Etc/UTC')
[simpledate.best_guess_utc(date) for date in ['1/6/2013 BST', '1/6/2013 EST', 'Tue, 18 Jun 2013 12:19:09 -0400']]
'''
[datetime.datetime(2013, 5, 31, 23, 0, tzinfo=<UTC>),
datetime.datetime(2013, 1, 6, 5, 0, tzinfo=<UTC>),
datetime.datetime(2013, 6, 18, 16, 19, 9, tzinfo=<UTC>)]
'''
datetime
paketi ile ilgili notlarım şimdilik bu kadar. İlerleyen zaman içerisinde yeni notlar ve örnekler eklemeye devam edeceğim.
- Dates and Times in R ↩
- Lubridate. Make Dealing with Dates a Little Easier ↩
- node-datetime. npm ↩
- Python DateTime, TimeDelta, Strftime(Format) with Examples ↩
- Bryan Weber. Using Python datetime to Work With Dates and Times ↩
- Basic Date and Time Types - strftime() and strptime() Format Codes ↩
- Python strftime cheatsheet ↩
- locale — Internationalization services. Python 3.x Documentation ↩
- Miguel Brito. (2020). How to Use datetime.timedelta in Python With Examples ↩
- Time series / date functionality. Pandas Documentation ↩
- Time deltas. Pandas Documentation ↩
- dateutil - powerful extensions to datetime ↩
- arrow. Better dates & times for Python ↩
- andrewcooke/simple-date. GitHub ↩