#!/usr/bin/env python3 # -*-coding:Utf-8 -* """Tools for timestamps of AaaaHorodatage class, Child class of AaaaHorodatage. Timestamp format = [0-9]+AAAAZ+/-HH:MM where [0-9]+ = the number of seconds from the epoch until the date entered, AAAA = the epoch of the timestamp, and Z+/-HH:MM the UTC offset (e.g for CEST, summertime: Z+02:00). The timezone and epoch are embedded. Class attribute(s) - epoch: class reference year of the timestamp (only for encoding). Range: 1000 <= epoch <= 9999. Default 2000. Several ranges and keyboard input are managed, but not exceptions. Help and download: https://gitlab.adullact.net/zenjo/AaaaHorodatage/tree/master """ ######################################### # GNU General Public License, version 3 # ############################################################################ # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see . # # # # Robert Sebille, Belgium, 2018 - # # # ############################################################################ # As compliant as possible with the PEP8 # # https://www.python.org/dev/peps/pep-0008/ # ############################################# import os import sys import math import time # value to test module # from ahordat import AaaaHorodatage # value for production from aaaa.ahordat import AaaaHorodatage class AaaaHorodatageTools(AaaaHorodatage): # For dev start # # in AaaaHorodatage: # année de référence (attribut de classe) # epoch = 1900 # private # attributs # def _get_ljm(self, i): # ljm = property(_get_ljm) # methodes # def _bissextile(self, an = 0): # def _input_entier(self, annonce=""): # def _calcul_encode(self): # def _cal def _input_entier(self, annonce=""):cul_decode(self, typ): # méthodes publiques # classe (cls) # def get_epoch(cls): # get_epoch = classmethod(get_epoch) # def set_epoch(cls, num): # set_epoch = classmethod(set_epoch) # instance (self) # def encode(self, d=""): # def decode(self, typ="string", t=0): # For dev end def __init__(self, ts=""): AaaaHorodatage.__init__(self, ts) # protected #douglas = open("aaaa/42", "r") #self._Aaaa42 = douglas.read() #douglas.close() def get_42(self): douglas = open("aaaa/42", "r") print(douglas.read()) douglas.close() print("Non fatal error 42: existential error 101010.") print("System not halted. L'histoire") print(" con") print(" ti") print(" n") print(" u") print(" e") print(" .") print(" .") print(" .\n") print("|101010 101010 101010 101010 101010 101010 101010 101010 101010\ 101010 101010 |\n") #get_42 = property(_get_42) # protected # # attributs # Special # def copy(self): tmp = AaaaHorodatageTools() tmp.ts = self.ts return tmp def __eq__(self, ts_object): """== operator""" aaaa = self.copy() aaaa_posix = aaaa.convert_aaaa2posix() ts_object_posix = ts_object.convert_aaaa2posix() return aaaa_posix == ts_object_posix def __ne__(self, ts_object): """!= operator""" aaaa = self.copy() aaaa_posix = aaaa.convert_aaaa2posix() ts_object_posix = ts_object.convert_aaaa2posix() return aaaa_posix != ts_object_posix def __gt__(self, ts_object): """> operator""" aaaa = self.copy() aaaa_posix = aaaa.convert_aaaa2posix() ts_object_posix = ts_object.convert_aaaa2posix() return aaaa_posix > ts_object_posix def __ge__(self, ts_object): """>= operator""" aaaa = self.copy() aaaa_posix = aaaa.convert_aaaa2posix() ts_object_posix = ts_object.convert_aaaa2posix() return aaaa_posix >= ts_object_posix def __lt__(self, ts_object): """< operator""" aaaa = self.copy() aaaa_posix = aaaa.convert_aaaa2posix() ts_object_posix = ts_object.convert_aaaa2posix() return aaaa_posix < ts_object_posix def __le__(self, ts_object): """<= operator""" aaaa = self.copy() aaaa_posix = aaaa.convert_aaaa2posix() ts_object_posix = ts_object.convert_aaaa2posix() return aaaa_posix <= ts_object_posix def __str__(self): """Return the string self.ts""" return self.get_ts() def __add__(self, seconds=0): """new_ts = ts_object + seconds. Overload of plus operator. self.ts will be updated Tips: - use dhms2second(d=0, h=0, m=0, s=0) method to convert days + hours + minutes + seconds in seconds - To add seconds to a new timestamp instance: new_ts_object = ts_object.copy() new_ts_object + seconds """ tmp = self.ts.split("Z") ts_offset = tmp[1] tmp = int(tmp[0]) ts_epoch = int(tmp % 10000) ts_seconds = int(tmp / 10000) ts_seconds += seconds self.ts = str(ts_seconds) + str(ts_epoch) + "Z" + ts_offset return self def __sub__(self, *nb_seconds_or_ts_object): """new_ts = ts_object - *nb_seconds_or_ts_object Overload of minus operator. if *nb_seconds_or_ts_object is ts_object, call self.ts.diffDays("string", *nb_seconds_or_ts_object.get_ts()), see this method. self.ts is NOT updated. if *nb_seconds_or_ts_object is a nb_seconds integer update and return self.ts - *nb_seconds self.ts seconds - seconds must be >= 0 (epoch-01-01) Tips: - use dhms2second(d=0, h=0, m=0, s=0) utility method to convert days + hours + minutes + seconds in seconds - To add seconds to a new timestamp instance: new_ts_object = ts_object.copy() new_ts_object - seconds """ if isinstance(nb_seconds_or_ts_object[0], AaaaHorodatageTools): return nb_seconds_or_ts_object[0].diffDays("string", self.get_ts()) if isinstance(nb_seconds_or_ts_object[0], int): seconds = nb_seconds_or_ts_object[0] tmp = self.ts.split("Z") ts_offset = tmp[1] tmp = int(tmp[0]) ts_epoch = int(tmp % 10000) ts_seconds = int(tmp / 10000) if ts_seconds >= seconds: ts_seconds -= seconds else: print("Fatal error 53: number of seconds to substract ", end="") print("to big in __sub__(seconds=0). Substract < ", end="") print(ts_epoch, "-01-01 (epoch of the timestamp)", sep="") print("Program halted.") sys.exit(53) self.ts = str(ts_seconds) + str(ts_epoch) + "Z" + ts_offset return self # protected # # méthodes # méthodes publiques # # class (cls) # instance (self) def diffDays(self, typ="string", ts2=0): """Difference between 2 timestamps in days, hours, minutes, seconds. ts2 - self.ts1. Usage: ts1_object.diffDays(, ) Offset UTC timestamp 1 must match offset UTC timestamp 2 and epoch timestamp 1 must match epoch timestamp 2. Return typ = - "seconds": return the number of seconds. - "string": return a string (+/-DDTHH:MM:SS). Default. - "list": return a list (fixed order). fixed order: sens_difference, day, hour, minutes, seconds. - "dict" or "dictionary": return a dict (any order). ts2 = 0 or none: keyboard input. ts2 eg: ts2_object.get_ts() """ # if keyboard if ts2 == 0: ts2 = input("Decode timestamp 2: ") # if arg # to do # Récupération des timestamp et test des offset utc ts1_split = self.ts.split("Z") ts2_split = ts2.split("Z") if ts1_split[1] != ts2_split[1]: print("Fatal error 51: offset UTC1 " + ts1_split[1] + " does not match offset UTC2 " + ts2_split[1] + "\nProgram halted.") print("Consider to standardize the 2 timestamps to Z (+00:00)") print(" using .tz2utc(timestamp1)") print(" using .tz2utc(timestamp2)") sys.exit(51) # recup ts1, ts2 ts1 = int(ts1_split[0]) ts2 = int(ts2_split[0]) epoch1 = ts1 % 10000 epoch2 = ts2 % 10000 ts1 = int(ts1 / 10000) ts2 = int(ts2 / 10000) # test des epoch if epoch1 != epoch2: print("Fatal error 52: epoch1 " + str(epoch1) + " does not match epoch2 " + str(epoch2) + "\nProgram halted.") print("Consider to standardize the 2 epochs") print(" using .convert2epoch(timestamp1, epoch)") print(" using .convert2epoch(timestamp2, epoch)") sys.exit(52) # ts2 > ts1 => sens diff = +, sinon - sens_diff = "+" if ts1 > ts2: ts1, ts2 = ts2, ts1 sens_diff = "-" dts = ts2 - ts1 secondes = dts % 60 minutes = int((dts / 60) % 60) heures = int((dts / (60 * 60)) % 24) jours = int(dts / (60 * 60 * 24)) if typ == "seconds": if sens_diff == "-": retour = -dts else: retour = dts if typ == "string": retour = (sens_diff + str(jours) + "T" + str(heures) + ":" + str(minutes) + ":" + str(secondes)) if typ == "list": retour = list() retour.append(sens_diff) retour.append(jours) retour.append(heures) retour.append(minutes) retour.append(secondes) if typ == "dict" or typ == "dictionary": retour = dict() retour["sensdiff"] = sens_diff retour["days"] = jours retour["hours"] = heures retour["minutes"] = minutes retour["seconds"] = secondes return retour def convert2epoch(self, epoch): """Convert an embedded epoch to an other 1000 <= epoch <= 9999 self.ts is updated """ ts_offset = self.ts.split("Z") ts_offset = self.offset_string2seconds(ts_offset[1]) save_offset = self.get_utc_local_offset() save_epoch = self.get_epoch() ts = self.decode("list", self.ts) self.set_epoch(epoch) self.set_utc_local_offset(ts_offset) ts = self.encode(ts) self.set_epoch(save_epoch) self.set_utc_local_offset(save_offset) self.ts = ts return self.ts def dhms2seconds(self, d=0, h=0, m=0, s=0): """Convert days + hours + minutes + seconds in seconds""" return d * self._get_nb_sec_par_jour() + h * 3600 + m * 60 + s def convert_aaaa2posix(self): """Return a Posix timestamp (UTC) from an Aaaa timestamp""" aaaa_ts = self.copy() aaaa_ts.convert2epoch(1970) aaaa_ts.tz2utc() #self.ts = save_local_ts tmp = aaaa_ts.get_ts().split("Z") ts_sec = int(tmp[0]) ts_sec = int(ts_sec / 10000) return ts_sec def convert_posix2aaaa(self, posix_ts): """Return an Aaaa timestamp from a Posix timestamp self.ts is updated posix_ts will be considered at UTC time. """ self.ts = str(posix_ts) + "1970Z+00:00" return self.ts def set_ts_same_epoch_offset(self, ts_object): """Convert ts_object to same epoch and UTC offset than self.ts ts_object.ts is updated """ ts_epoch = self.get_ts_epoch() tmp = self.get_ts() tmp = tmp.split("Z") ts_offset = tmp[1] ts_object.tz2utc() ts_object.utc2tz(ts_offset) ts_object.convert2epoch(ts_epoch) return ts_object if __name__ == "__main__": # at top, # from ahordat import AaaaHorodatage # to test module h = AaaaHorodatageTools() h.encode((2001, 1, 1, 10, 10, 10)) print(h.decode()) h2 = h + h.dhms2seconds(1, 2, 10, 20) print(h2.get_ts()) print(h.decode(), " - ", h2.decode()) sys.exit() k = AaaaHorodatageTools() print(k.get_utc_local_offset()) print(k.get_utc_local_offset("string")) myKCEST = k.encode([2001, 2, 20, 20, 15, 30]) print(myKCEST) print(k.decode('string', myKCEST), "\n---") print(k.convert2epoch(myKCEST, 1900))