29 Get current date or datetime in ISO format
30 but without delimiters like 20240409 or 20240409T090245
31 inctime: bool whether to include time part with T prefix
32 tz: optional number hours timezone offset from UTC (e.g. Dallas TX is -5, Kolkata India is +5.5, New York NY is -4),
33 otherwise the computer's time zone is used so depends on server settings.
34 Returns string starting with notok: if error
39 dtime_secs_since_epoch:float=-999999
42 dtime_secs_since_epoch=
time()
43 if len(tz)>0
and numfuncs.is_real(tz):
44 dval= dtime_secs_since_epoch + round(float(tz),1) * 3600
46 dval= dtime_secs_since_epoch
47 time_obj= localtime(dval)
49 result= strftime(
"%Y%m%dT%H%M%S", time_obj)
51 result= strftime(
"%Y%m%d", time_obj)
52 except (RuntimeError, ValueError, OSError)
as err:
53 result=
"notok:" + str(err)
58 Determines if string is an ISO DateTime
60 timereq: bool if time part is required. This is demarcated by either
61 T or a space after the date part as with 20240420T0730 or 20240420 0730
63 All delimiters will be removed (- /) in date part, (:) in time part.
64 Returns string as either false or true:<newdatetime>, or starts
92 elif timereq
and " " in strin:
95 timepart= strin[n1+1:]
99 dayspermonth.append(31)
100 dayspermonth.append(28)
101 dayspermonth.append(31)
102 dayspermonth.append(30)
103 dayspermonth.append(31)
104 dayspermonth.append(30)
105 dayspermonth.append(31)
106 dayspermonth.append(31)
107 dayspermonth.append(30)
108 dayspermonth.append(31)
109 dayspermonth.append(30)
110 dayspermonth.append(31)
112 if timereq
and len(timepart)==0:
117 n1=datepart.find(delim)
124 elif len(datepart)>=4:
130 if len(txt1)==4
and numfuncs.is_int(txt1):
136 if not fmterr
and len(txt2)==2
and numfuncs.is_int(txt2):
138 if nmo<=0
or nmo>=13:
142 if not fmterr
and len(txt3)==2
and numfuncs.is_int(txt3):
144 if ndy<=0
or ndy>=31:
148 if not fmterr
and timereq:
154 if timepart.endswith(
"z"):
156 timepart=timepart[:len(timepart)-1]
157 elif "+" in timepart:
158 n1=timepart.find(
"+")
160 timepart=timepart[:n1].strip()
161 elif "-" in timepart:
162 n1=timepart.find(
"-")
164 timepart=timepart[:n1].strip()
167 n1=timepart.find(delim)
174 elif len(timepart)>2:
178 if len(timepart)==6
or (
"." in timepart
and len(timepart)>7):
185 if len(txt1)!=2
or not numfuncs.is_int(txt1):
190 if len(txt2)!=2
or not numfuncs.is_int(txt2):
195 if len(txt3)!=2
or not numfuncs.is_int(txt3):
199 if len(txt4)>0
and not numfuncs.is_int(txt4):
213 n1= 29
if is_year_leap(nyr)
else 28
215 n1= dayspermonth[nmo-1]
233 result= txt1 + txt2 + txt3
245 result += txt1 + txt2 + txt3
246 result =
"true:" + result
251 except (RuntimeError,ValueError,OSError)
as err:
252 result=
"notok:" + str(err)
257 Excel numeric date to ISO format
259 Converts a date in numeric excel format into ISO8601 yyyyMMdd format.
260 Fractional days are removed. Jan 1 1900 is 1. Anything less than 1 is error.
261 Example: 44106 = 20201002, 45393 = 20240411, 21012=19570711
262 Return result as yyyyMMdd. Starts with notok: if there is an error
286 dayspermonth.append(31)
287 dayspermonth.append(28)
288 dayspermonth.append(31)
289 dayspermonth.append(30)
290 dayspermonth.append(31)
291 dayspermonth.append(30)
292 dayspermonth.append(31)
293 dayspermonth.append(31)
294 dayspermonth.append(30)
295 dayspermonth.append(31)
296 dayspermonth.append(30)
297 dayspermonth.append(31)
298 dayspermonth.append(29)
309 ddays_400= ddays_100*4
315 str1=str1[:str1.find(
".")]
318 raise ValueError(
"min number to supply is 1 not: " + str1)
321 if dval_days>ddays_400:
322 nyrs_400= math.floor(dval_days/ddays_400)
323 dval_days -= nyrs_400 * ddays_400
324 if dval_days> ddays_100:
325 nyrs_100= math.floor(dval_days/ddays_100)
326 dval_days -= nyrs_100 * ddays_100
327 if dval_days > ddays_4:
328 nyrs_4= math.floor(dval_days/ddays_4)
329 dval_days -= nyrs_4 * ddays_4
330 if dval_days > ddays_1:
331 nyrs_1= math.floor(dval_days/ddays_1)
332 dval_days -= nyrs_1 * ddays_1
334 curyr= 1900 + 400*nyrs_400 + 100*nyrs_100 + 4*nyrs_4 + nyrs_1
335 isleap= is_year_leap(curyr)
342 ndays += dayspermonth[12]
344 ndays += dayspermonth[i]
347 curday=dval_days- ndaysprev
350 curday= max(curday,1)
360 except (RuntimeError,ValueError,OSError)
as err:
361 result=
"notok:" + str(err)
388 Converts a datetime into ISO8601 format based on specified format.
389 Time portions should be removed prior to sending into this method.
390 Four delimiters in date part will be automatically detected: ( - / _ . )
392 datein: incoming date string not in ISO8601 and without time part.
393 formatin: required unless detectfmt is True
394 mmddyy, mmdyy, mdyy, mmddyyyy, mmdyyyy, mdyyyy,
395 ddmmyy, ddmyy, dmyy, ddmmyyyy, ddmyyyy, dmyyyy,
396 yymmdd, yymmd, yymd, yyyymmdd, yyyymmd, yyyymd,
397 yyyyddd (3 digit day number within year),
398 yyyyMMMdd, ddMMMyyyy (MMM = 3 letter month title like 'JAN'),
399 'MONTHdd,yyyy', 'ddMONTH,yyyy', yyyyMONTHdd, ddMONTHyyyy, yyMONTHdd, ddMONTHyy (MONTH full title),
400 *dmmyyyy, mm*dyyyy, *mddyyyy, dd*myyyy (*= can be 1 or 2 characters)
402 With these formats, incoming string must have all characters required so for mmddyyyy there must be
403 8 characters meaning 1122011 fails but 01122011 is good.
404 Leading title of day is removed like for Wednesday, March 14, 2001 which will be changed to
405 March 14, 2001 and then will match formatin of MONTHdd,yyyy since spaces are removed
406 detectfmt: optional bool when True the format will be detected if possible. To do so, the date
407 part should have a delimiter ( / - ) like 12/20/2021 or 2024-04-02, and preferably
408 where day value is unambiguous relative to month (i.e. > 12 )
409 Returns - result as yyyymmdd with suffix (dateformat) if detectfmt=True. Starts with 'notok:' if there is an error
414 hash_month_names:dict={}
415 hash_month_longnames:dict={}
416 hash_day_names:dict={}
417 hash_day_longnames:dict={}
418 has_short_month:bool=
False
419 has_long_month:bool=
False
421 month_name_used:str=
""
443 dayspermonth.append(31)
444 dayspermonth.append(28)
445 dayspermonth.append(31)
446 dayspermonth.append(30)
447 dayspermonth.append(31)
448 dayspermonth.append(30)
449 dayspermonth.append(31)
450 dayspermonth.append(31)
451 dayspermonth.append(30)
452 dayspermonth.append(31)
453 dayspermonth.append(30)
454 dayspermonth.append(31)
455 dayspermonth.append(29)
457 hash_month_names[
"jan"]=
"01"
458 hash_month_names[
"feb"]=
"02"
459 hash_month_names[
"mar"]=
"03"
460 hash_month_names[
"apr"]=
"04"
461 hash_month_names[
"may"]=
"05"
462 hash_month_names[
"jun"]=
"06"
463 hash_month_names[
"jul"]=
"07"
464 hash_month_names[
"aug"]=
"08"
465 hash_month_names[
"sep"]=
"09"
466 hash_month_names[
"oct"]=
"10"
467 hash_month_names[
"nov"]=
"11"
468 hash_month_names[
"dec"]=
"12"
469 hash_month_longnames[
"january"]=
"01"
470 hash_month_longnames[
"february"]=
"02"
471 hash_month_longnames[
"march"]=
"03"
472 hash_month_longnames[
"april"]=
"04"
473 hash_month_longnames[
"may"]=
"05"
474 hash_month_longnames[
"june"]=
"06"
475 hash_month_longnames[
"july"]=
"07"
476 hash_month_longnames[
"august"]=
"08"
477 hash_month_longnames[
"september"]=
"09"
478 hash_month_longnames[
"october"]=
"10"
479 hash_month_longnames[
"november"]=
"11"
480 hash_month_longnames[
"december"]=
"12"
482 hash_day_names[
"mon"]=1
483 hash_day_names[
"tue"]=2
484 hash_day_names[
"wed"]=3
485 hash_day_names[
"thu"]=4
486 hash_day_names[
"fri"]=5
487 hash_day_names[
"sat"]=6
488 hash_day_names[
"sun"]=7
489 hash_day_longnames[
"monday"]=1
490 hash_day_longnames[
"tuesday"]=2
491 hash_day_longnames[
"wednesday"]=3
492 hash_day_longnames[
"thursday"]=4
493 hash_day_longnames[
"friday"]=5
494 hash_day_longnames[
"saturday"]=6
495 hash_day_longnames[
"sunday"]=7
497 datein=datein.lower().strip()
498 formatin=formatin.lower().strip()
501 raise ValueError(
"no datein")
502 if len(formatin)==0
and not detectfmt:
503 raise ValueError(
"missing formatin")
505 for k,v
in hash_day_longnames.items():
506 if datein.startswith(k):
508 datein=datein[(len(k)+1):].strip()
509 if datein.startswith(
","):
510 datein=datein[1:].strip()
513 for k,v
in hash_day_names.items():
514 if datein.startswith(k):
519 datein=datein[(n1+1):].strip()
521 datein=datein[(n2+1):].strip()
523 datein=datein[(len(k)+1):].strip()
524 if datein.startswith(
","):
525 datein=datein[1:].strip()
528 for k,v
in hash_month_longnames.items():
534 if not has_long_month:
535 for k,v
in hash_month_names.items():
542 formatin=formatin.replace(
"-",
"")
544 formatin=formatin.replace(
"/",
"")
546 formatin=formatin.replace(
"_",
"")
548 formatin=formatin.replace(
".",
"")
560 if not "month" in formatin
and not "*" in formatin:
562 if len(delimin)>0
and delimin
in str1:
563 str1=str1.replace(delimin,
"")
564 if len(str1)> len(formatin):
565 raise ValueError(
"too many characters for formatin: " + str(len(str1)) +
" for " + formatin)
566 if len(str1)< len(formatin):
567 raise ValueError(
"too few characters for formatin: " + str(len(str1)) +
" for " + formatin)
568 elif "*" in formatin:
569 if len(datein)< (len(formatin)-1):
570 raise ValueError(
"too few characters #= " + str(len(datein)) +
" for formatin: " + formatin)
573 if detectfmt
and len(formatin)==0
and len(delimin)>0:
574 nidx= datein.find(delimin)
576 txt1= datein[nidx+1:]
577 nidx= txt1.find(delimin)
586 if numfuncs.is_int(txt1):
588 if numfuncs.is_int(txt2):
592 str1=
"d" if len(txt1)==1
else "dd"
593 str2=
"m" if len(txt2)==1
else "mm"
595 str1=
"m" if len(txt1)==1
else "mm"
596 str2=
"d" if len(txt2)==1
else "d"
597 formatin=
"yyyy" + str1 + str2
599 txt1= datein[nidx+1:]
603 if numfuncs.is_int(txt2):
605 nidx= txt1.find(delimin)
611 elif len(txt1)<4
and numfuncs.is_int(txt1):
622 if numfuncs.is_int(txt1):
626 str1=
"d" if len(txt)==1
else "dd"
627 str2=
"m" if len(txt1)==1
else "mm"
628 str3=
"yyyy" if len(txt2)>=4
else "yy"
630 str1=
"m" if len(txt)==1
else "mm"
631 str2=
"d" if len(txt1)==1
else "dd"
632 str3=
"yyyy" if len(txt2)>=4
else "yy"
633 formatin= str1 + str2 + str3
637 if numfuncs.is_int(txt2):
641 str1=
"d" if len(txt)==1
else "dd"
642 str2=
"yy" if len(txt1)==2
else "yyyy"
643 str3=
"m" if len(txt2)==1
else "mm"
645 str1=
"m" if len(txt)==1
else "mm"
646 str2=
"yy" if len(txt1)==2
else "yyyy"
647 str3=
"d" if len(txt2)==1
else "dd"
648 formatin= str1 + str2 + str3
651 raise ValueError(
"no formatin")
653 if "dmonthy" in formatin
or "ymonthd" in formatin:
654 datein=datein.replace(
" ",
"")
655 if formatin
in [
"yyyymonthdd",
"yymonthdd"]:
656 if formatin.startswith(
"yyyy"):
662 if (has_long_month
or has_short_month):
664 if len(datein)> len(month_name_used):
665 dy= datein[len(month_name_used):]
668 elif formatin
in [
"ddmonthyyyy",
"ddmonthyy"]:
671 if (has_long_month
or has_short_month):
673 if len(datein)> len(month_name_used):
674 yr= datein[len(month_name_used):]
675 elif formatin
in [
"monthdd,yyyy",
"ddmonth,yyyy"]:
676 datein=datein.replace(
" ",
"")
681 if len(month_name_used)>0:
683 if formatin.startswith(
"dd"):
684 dy=datein[:datein.find(month_name_used)]
686 dy=datein[len(month_name_used):]
688 liststr=datein.split(delimin)
689 if formatin
in [
"ddmmmyyyy",
"ddmmmyy"]:
696 elif formatin
in [
"yyyymmmdd",
"yymmmdd"]:
703 elif formatin
in [
"",
"mmddyy",
"mddyy",
"mmdyy",
"mdyy",
"mmddyyyy",
"mddyyyy",
"mmdyyyy",
"mdyyyy"]:
710 elif formatin
in [
"ddmmyy",
"ddmyy",
"dmmyy",
"dmyy",
"ddmmyyyy",
"ddmyyyy",
"dmmyyyy",
"dmyyyy"]:
717 elif formatin
in [
"yyddmm",
"yyddm",
"yydmm",
"yydm",
"yyyyddmm",
"yyyyddm",
"yyyydmm",
"yyyydm"]:
724 elif formatin
in [
"yymmdd",
"yymdd",
"yymmd",
"yymd",
"yyyymmdd",
"yyyymdd",
"yyyymmd",
"yyyymd"]:
731 elif formatin==
"yyyyddd":
736 if len(dy)>0
and numfuncs.is_int(dy):
739 isleap=is_year_leap(int(yr))
743 n2 = dayspermonth[12]
753 raise ValueError(
"unknown date format supplied: " + formatin)
754 elif formatin
in [
"ddmmmyyyy",
"ddmmmyy"]:
755 if len(month_name_used)>0:
759 yr=datein[(datein.find(month_name_used)+len(month_name_used)):]
760 elif formatin
in [
"yyyymmmdd",
"yymmmdd"]:
761 if len(month_name_used)>0:
764 yr=datein[:datein.find(month_name_used)]
765 dy=datein[(datein.find(month_name_used)+len(month_name_used)):]
766 elif "*" in formatin:
767 if formatin.endswith(
"yyyy"):
769 if formatin.startswith(
"*dmm"):
775 elif formatin.startswith(
"*mdd"):
781 elif formatin.startswith(
"dd*m"):
787 elif formatin.startswith(
"mm*d"):
793 elif formatin
in [
"mmddyy",
"mmddyyyy",
"mmdyy",
"mmdyyyy"]:
805 if "mdy" in formatin:
814 if formatin.endswith(
"dyy"):
819 if "mdy" in formatin
and len(dy)>1:
821 elif formatin
in [
"mddyy",
"mddyyyy",
"mdyy",
"mdyyyy"]:
833 if "mdy" in formatin:
842 if formatin.endswith(
"dyy"):
847 if "mdy" in formatin
and len(dy)>1:
849 elif formatin
in [
"ddmmyy",
"ddmmyyyy",
"ddmyy",
"ddmyyyy"]:
862 if "dmy" in formatin:
869 if formatin.endswith(
"myy"):
874 elif formatin
in [
"dmmyy",
"dmmyyyy",
"dmyy",
"dmyyyy"]:
887 if "dmy" in formatin:
894 if formatin.endswith(
"myy"):
899 elif formatin
in [
"yyddmm",
"yyddm",
"yydmm",
"yydm"]:
912 if "ydm" in formatin:
919 if formatin.endswith(
"dm"):
922 elif formatin
in [
"yyyyddmm",
"yyyyddm",
"yyyydmm",
"yyyydm"]:
935 if "ydm" in formatin:
942 if formatin.endswith(
"dm"):
945 elif formatin
in [
"yymmdd",
"yymmd",
"yymdd",
"yymd"]:
958 if "ymd" in formatin:
965 if formatin.endswith(
"md"):
968 elif formatin
in [
"yyyymmdd",
"yyyymmd",
"yyyymdd",
"yyyymd"]:
981 if "ymd" in formatin:
988 if formatin.endswith(
"md"):
991 elif formatin==
"yyyyddd":
998 isleap=is_year_leap(int(yr))
999 if len(dy)>0
and numfuncs.is_int(dy):
1005 n2 = dayspermonth[12]
1007 n2 = dayspermonth[i]
1015 raise ValueError(
"unknown date format supplied: " + formatin)
1017 if len(yr)==2
and numfuncs.is_int(yr):
1019 str1= get_current_iso_datetime()
1021 if not str1.startswith(
"notok:")
and len(str1)>=4:
1023 if numfuncs.is_int(str1):
1025 if prior_yr_min<= nyr <=prior_yr_max:
1029 if numfuncs.is_int(yr):
1031 if numfuncs.is_int(dy):
1035 nmo= int(hash_month_longnames[mo])
1036 elif has_short_month:
1037 nmo= int(hash_month_names[mo])
1038 elif numfuncs.is_int(mo):
1042 raise ValueError(
"year is less than 1: " + str(nyr))
1051 n1=dayspermonth[nmo-1]
1053 raise ValueError(
"days are greater than month max. Month=" + str(nmo) +
",days=" + str(ndy))
1055 raise ValueError(
"month is less than 1: " + str(nmo))
1057 raise ValueError(
"month is greater than 12: " + str(nmo))
1060 raise ValueError(
"day is less than 1: " + str(ndy))
1062 raise ValueError(
"day is greater than 31: " + str(ndy))
1078 result= yr + mo + dy
1080 result +=
"(" + formatin +
")"
1081 except (RuntimeError,ValueError,OSError)
as err:
1082 result=
"notok:" + str(err)