Tider

Når du eksperimenterer med tidszoner i programmering, kan det være meget svært at overskue, hvilke funktioner, man skal bruge hvornår og til hvad. Det skyldes dels at tid ikke er konstant men er relativ, og dels at vi skal følge nogle fastlagte standarder.

Coordinated Universal Time : UTC

Verden er delt op i flere forskellige tidszoner. Der findes fx en inden for krig, landespecificerede tider og en nautisk tidszone. Den tid som vi bruger i hverdagen er UTC-tidszonen, som vi ofte kalder Greenwich Mean Time eller bare GMT.

UTC er koordineret efter longitudes medridian, som er defineret som 0 grader. Hvis du har besøgt Greenwich laboratorium har du måske endda set det fysiske bevis på, hvor meridianen skærer.

Skæringspunktet deler den vestlige halvkugle, som har et maks-punkt på 179 grader fra Greenwhich, og den østlige halvkugle som ligeledes har et maks-punkt på 179 grader fra skæringspunktet.

By TimeZonesBoy – US Central Intelligence Agency, Public Domain, https://commons.wikimedia.org/w/index.php?curid=22556731

Nu er det ikke en artikel om kartografi. Hertil ved jeg slet ikke nok.

Naive og Aware

Når man eksperimenterer med tider i programmering er det værd, at bidde mærke i, at man ofte har to valg:

Naive = indeholder sjældent store mængder informationer. Det tager afsæt i dets omgivelser. Dvs. at den nok kan finde ud af hvad klokken er og hvilken dato det er, lokalt. Eller hvis vi indstiller et ur, som vi gør senere, hvor vi vil se på Apollo 11s månelanding.

Aware = Den naive tid er i stand til at lokalisere sig selv i forhold til dets omgivelser. Dvs. i forhold til andre tidszoner, og hvis der sker politiske forandringer osv. Aware er altså et noget mere komplekst tidsobjekt at arbejde med end det naive.

time

Den nemmeste måde at finde tidspunkter i er med time-modulet. Vi kender bl.a. modulet for spilprogrammering, når vi bruger time.sleep(2) for at skabe suspence i vores spil.

time.asctime() # klokken i computeren

import time

time.asctime() 
# Wed Mar  4 12:14:01 2020'

# antal sekunder bagud Greenwich Mean Time
time.altzone 
# -7200

time.localtime()  
# time.struct_time(tm_year=2020, tm_mon=3, tm_mday=6, tm_hour=1, tm_min=16, tm_sec=8, tm_wday=4, tm_yday=66, tm_isdst=0)

time.time()
# antal sekunder siden UTC i 1970

pytz

pytz er et tidszone-modul i Python. Modullet benytter data fra tz databasen.

UTC: Klokken i (næsten) alle tidszonerne er synkroniseret fra 1970. Der var nogle lande som ikke gjorde det, og der var områder, som end ikke fandtes dengang, men som findes i dag. Som sagt: tid er relativt. Man bør dog anse alle tidspunkter for synkroniserede. Tidszonerne er delt op i:

Regioner: Africa, America, Antarctica, Arctic, Asia, Atlantic, Australia, Europe, Indian, og Pacific.

Lokaliteter: Fx. New_York, Copenhagen og Fiji

Man søger lokaliter ved først at skrive region og dernæst lokalitet. Fx America/New_York, Europe/Copenhagen, Pacifc/Fiji osv.

Listen over alle regioner og tidszoner kan du se her.

Inde i eksempelvis din IDLE shell eller i ipython kan du importere pytz, som følger med Pythons som standard.

Lad os først se den loope over alle tidszonerne.

import pytz

for i in pytz.all_timezones:
    print(i)

Ovenstående giver dig et overblik over alle tidszoner. Hvis du derimod vil indhente info om de mest benyttede regioner og lokaliter kan du i stedet bruges common_timezones funktionen.

import pytz 
for i in pytz.common_timezones:                    
    print(i)

Lad os prøve at se om vi kan finde rundt i tidszonerne.

import pytz
pytz.timezone("US/Eastern")
pytz.timezone("Europe/Copenhagen")

Prøv eventuelt at søge på flere tidszoner.

De forskellige landekoder kan printes ved nedenstående script. Fx har Tyskland, DE, Danmark, DK, Bulgarien, BG, Rusland, RU, Norge, NO. Prøv at se om du kan finde landekoder, som du er usikker på.

for key, val in pytz.country_names.items():
    print(key, "=", val, end=",")

Du kan også søge på specifikke landekoder:

print(pytz.country_names["BE"])
# Belgium

Funktioner

import pytz

def landekoder(kode): 
    land = kode.upper() 
    print(kode, "=", pytz.country_names[kode]) 

Prøv nu at se hvad de andre funktioner i pytz indeholder ved at skrive pytz efterfulgt af tabulator = pytz.<TAB>

datetime

datetime-modulet er relativt simpelt at komme igang med. Selve modulet indeholder en række gode klasser som nemt lader dig implementere forskellige typer tid.

Vi kan fx finde dagen gennem følgende script:

import detatime

nu = datetime.date.today()

nu # printer år, måned og dag = 2020.03.04.

# find frem til, hvor længe siden det er du havde 
# fødselsdag

fdag = datetime.date(nu.year, 2, 14) # 14.2
fdag # datetime.date(2020, 2, 14)
tid_fra_fdag = abs(fdag - idag)
tid_fra_fdag # 19 dage siden hvilket passer

Tidernes rækkefølge

I min optik bør man vænne sig til den amerikanske type at skrive dato på, da langt størstedelen af de programmer, som produceres er af amerikanske virksomheder. Om ikke andet skal man i hvert fald aftale, hvordan tiderne skal se ud, hvis man arbejder på globale projekter.

strftime Hvis du ønsker at lave om på tidernes rækkefølge, kan du bruge strftime. Vi har stadig udgangspunkt i vores kode fra ovenstående eksempel. Lad os først se på, hvad idag-objektet indeholder. Vi ved at den viser dataoen ved at skrive datetime.date. Men vi kan også se hvad den ellers indeholder af paramentrer.

nu # datetime.date(2020, 3, 4)

# nu er et objekt og kan derfor ikke printes i et >>> #loop. Lad os derfor konvertere vores objekt til # en tuple.

t_nu = nu.timetuple()
nu 
# (tm_year=2020, tm_mon=3, tm_mday=4,
#tm_hour=0, # tm_min=0, tm_sec=0, tm_wday=2, 
#tm_yday=64, 
# tm_isdst=-1)

for i in t_nu:
    print(i)
2020 # Årstal
3 # Måned
4 # Dag
0 # time
0 # minut
0 # sekund
2 # ugedag 2 = onsdag
64 # 64. dag i året.
-1 # En time fra UTC 

ISO : International Organization for Standardization

Mere end 165 lande har tilsluttet sig de internationale standarder, ISO. ISO-standard bruges inden for alt lige fra lægemidler til tider. Du kan gå på opdagelse på ISO’s egen hjemmeside på iso.org og du kan læse mere om kalendersystemet inde på wikipedia. Og husk, at ISO ikke er det samme som UTC. UTC er som tidliger nævnt tidszoner, og disse har ISO vedtaget som standard.

Lad os få en kaldender frem:

iso_kal = idag.isocalender()
iso_kal # (2020, 10, 3)
for i in isoc:
   print(i)
2020 # år
10 # uge
3 # måned

# Konverter til isoformat
idag.isoformat()
20-03-04
Konverter til hverdagsbrug
idag.strftime("%d/%m/%y") #%d = dag %m = md %y = år
'04/03/20'
idag.strftime("%A %d. %B %Y")

Formateringer

Da der findes mange formater at skrive datoer ind på, vil jeg her komme med nogle bud over, hvad man kan gøre. I Danmark er vi lidt specielle mht. vores brugt af tidspunkter, da vi som sagt ikke følger den mere gængse datalogiske struktur med 2020.03.04. I stedet benytter vi 2020.04.03, hvilket faktisk bruges mest inden for forsvaret, verden over. Vi har dog taget den til os, som primær struktur for, at vise datoer.

By NASA – http://history.nasa.gov/apollo_patches.html (direct link), Public Domain, https://commons.wikimedia.org/w/index.php?curid=1049515

Lad os i dette eksempel tage udgangspunkt i Apollo 11’s mission. De lettede fra jorden kl: 08:32PM 16. juni 1969

Ved at benytte os af strftime() funktionen, kan vi omskrive datoen i Python vha såkaldte direktiver. Se mere på python.org

import datetime

launch = datetime.datetime(1969, 6, 16, 8, 32) 

launch.strftime("%B %d, %Y") 
# June 16, 1969

launch.strftime("%Y/%m/%d") 
# 1969/06/16

launch.strftime("%d %b %y") 
# 16 Jun 69'

launch.strftime("%Y-%m-%d %H:%M:%S")  
# 1969-06-16 08:32:00'

launch.strftime("%c") 
# Mon Jun 16 08:32:00 1969

launch.isoformat() 
# 1969-06-16T08:32:00

launch.day 
# 16

Ekstra

Lad os se på et eksempel, hvor vi udregner tiden der er gået fra månelandingen til i dag. Det er værd at lægge mærke til, at selvom UTC først blev standard i 1970, virker denne udregning.

import pytz 
import datetime 

launch = datetime.datetime(1969, 6, 16, 8, 32) 

nu = datetime.datetime.utcnow()   

stamping = (nu - utc).total_seconds()  
stamping # 1600614786.819377

Sekunder til dage.

Det er mange sekunder siden, at månelandingen foregik, og det kræver vist, at vi indordner sekunder til antal dage.

import pytz

str(datetime.timedelta(seconds=1600614786.819377))

# '18525 days, 15:13:06.819377'

Kalender

Det sidste tidsmodul er calender-modulet. Modulet lader os bruge funktionerne til at se på kalender-specifikationer.

import calendar

kalender = calendar.month(2020, 3)  

print(kalender)