gam7 7.20.3__py3-none-any.whl → 7.21.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of gam7 might be problematic. Click here for more details.

gam/__init__.py CHANGED
@@ -25,17 +25,15 @@ https://github.com/GAM-team/GAM/wiki
25
25
  """
26
26
 
27
27
  __author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
28
- __version__ = '7.20.03'
28
+ __version__ = '7.21.00'
29
29
  __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
30
30
 
31
31
  #pylint: disable=wrong-import-position
32
32
  import base64
33
- import calendar as calendarlib
34
33
  import codecs
35
34
  import collections
36
35
  import configparser
37
36
  import csv
38
- import datetime
39
37
  from email.charset import add_charset, QP
40
38
  from email.generator import Generator
41
39
  from email.header import decode_header, Header
@@ -109,7 +107,7 @@ from cryptography.x509.oid import NameOID
109
107
  if not getattr(sys, 'frozen', False):
110
108
  sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
111
109
 
112
- from dateutil.relativedelta import relativedelta
110
+ import arrow
113
111
 
114
112
  from pathvalidate import sanitize_filename, sanitize_filepath
115
113
 
@@ -120,6 +118,10 @@ from google.auth.jwt import Credentials as JWTCredentials
120
118
  import google.oauth2.service_account
121
119
  import google_auth_oauthlib.flow
122
120
  import google_auth_httplib2
121
+ import googleapiclient
122
+ import googleapiclient.discovery
123
+ import googleapiclient.errors
124
+ import googleapiclient.http
123
125
  import httplib2
124
126
 
125
127
  httplib2.RETRIES = 5
@@ -149,12 +151,6 @@ import gdata.apps.audit
149
151
  import gdata.apps.audit.service
150
152
  import gdata.apps.contacts
151
153
  import gdata.apps.contacts.service
152
- # Import local library, does not include discovery documents
153
- import googleapiclient
154
- import googleapiclient.discovery
155
- import googleapiclient.errors
156
- import googleapiclient.http
157
- from iso8601 import iso8601
158
154
 
159
155
  IS08601_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S%:z'
160
156
  RFC2822_TIME_FORMAT = '%a, %d %b %Y %H:%M:%S %z'
@@ -163,7 +159,7 @@ def ISOformatTimeStamp(timestamp):
163
159
  return timestamp.isoformat('T', 'seconds')
164
160
 
165
161
  def currentISOformatTimeStamp(timespec='milliseconds'):
166
- return datetime.datetime.now(GC.Values[GC.TIMEZONE]).isoformat('T', timespec)
162
+ return arrow.now(GC.Values[GC.TIMEZONE]).isoformat('T', timespec)
167
163
 
168
164
  Act = glaction.GamAction()
169
165
  Cmd = glclargs.GamCLArgs()
@@ -213,6 +209,7 @@ ONE_GIGA_10_BYTES = 1000000000
213
209
  ONE_KILO_BYTES = 1024
214
210
  ONE_MEGA_BYTES = 1048576
215
211
  ONE_GIGA_BYTES = 1073741824
212
+ DAYS_OF_WEEK = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
216
213
  SECONDS_PER_MINUTE = 60
217
214
  SECONDS_PER_HOUR = 3600
218
215
  SECONDS_PER_DAY = 86400
@@ -1843,13 +1840,13 @@ def getStringWithCRsNLsOrFile():
1843
1840
  return (unescapeCRsNLs(getString(Cmd.OB_STRING, minLen=0)), UTF8, False)
1844
1841
 
1845
1842
  def todaysDate():
1846
- return datetime.datetime(GM.Globals[GM.DATETIME_NOW].year, GM.Globals[GM.DATETIME_NOW].month, GM.Globals[GM.DATETIME_NOW].day,
1847
- tzinfo=GC.Values[GC.TIMEZONE])
1843
+ return arrow.Arrow(GM.Globals[GM.DATETIME_NOW].year, GM.Globals[GM.DATETIME_NOW].month, GM.Globals[GM.DATETIME_NOW].day,
1844
+ tzinfo=GC.Values[GC.TIMEZONE])
1848
1845
 
1849
1846
  def todaysTime():
1850
- return datetime.datetime(GM.Globals[GM.DATETIME_NOW].year, GM.Globals[GM.DATETIME_NOW].month, GM.Globals[GM.DATETIME_NOW].day,
1851
- GM.Globals[GM.DATETIME_NOW].hour, GM.Globals[GM.DATETIME_NOW].minute,
1852
- tzinfo=GC.Values[GC.TIMEZONE])
1847
+ return arrow.Arrow(GM.Globals[GM.DATETIME_NOW].year, GM.Globals[GM.DATETIME_NOW].month, GM.Globals[GM.DATETIME_NOW].day,
1848
+ GM.Globals[GM.DATETIME_NOW].hour, GM.Globals[GM.DATETIME_NOW].minute,
1849
+ tzinfo=GC.Values[GC.TIMEZONE])
1853
1850
 
1854
1851
  def getDelta(argstr, pattern):
1855
1852
  if argstr == 'NOW':
@@ -1862,22 +1859,22 @@ def getDelta(argstr, pattern):
1862
1859
  sign = tg.group(1)
1863
1860
  delta = int(tg.group(2))
1864
1861
  unit = tg.group(3)
1865
- if unit == 'y':
1866
- deltaTime = datetime.timedelta(days=delta*365)
1867
- elif unit == 'w':
1868
- deltaTime = datetime.timedelta(weeks=delta)
1869
- elif unit == 'd':
1870
- deltaTime = datetime.timedelta(days=delta)
1871
- elif unit == 'h':
1872
- deltaTime = datetime.timedelta(hours=delta)
1873
- elif unit == 'm':
1874
- deltaTime = datetime.timedelta(minutes=delta)
1862
+ if sign == '-':
1863
+ delta = -delta
1875
1864
  baseTime = todaysDate()
1876
1865
  if unit in {'h', 'm'}:
1877
- baseTime = baseTime+datetime.timedelta(hours=GM.Globals[GM.DATETIME_NOW].hour, minutes=GM.Globals[GM.DATETIME_NOW].minute)
1878
- if sign == '-':
1879
- return baseTime-deltaTime
1880
- return baseTime+deltaTime
1866
+ baseTime = baseTime.shift(hours=GM.Globals[GM.DATETIME_NOW].hour, minutes=GM.Globals[GM.DATETIME_NOW].minute)
1867
+ if unit == 'y':
1868
+ return baseTime.shift(days=delta*365)
1869
+ if unit == 'w':
1870
+ return baseTime.shift(weeks=delta)
1871
+ if unit == 'd':
1872
+ return baseTime.shift(days=delta)
1873
+ if unit == 'h':
1874
+ return baseTime.shift(hours=delta)
1875
+ if unit == 'm':
1876
+ return baseTime.shift(minutes=delta)
1877
+ return baseTime
1881
1878
 
1882
1879
  DELTA_DATE_PATTERN = re.compile(r'^([+-])(\d+)([dwy])$')
1883
1880
  DELTA_DATE_FORMAT_REQUIRED = '(+|-)<Number>(d|w|y)'
@@ -1916,7 +1913,7 @@ def getYYYYMMDD(minLen=1, returnTimeStamp=False, returnDateTime=False, alternate
1916
1913
  elif argstr == 'NEVER':
1917
1914
  argstr = NEVER_DATE
1918
1915
  try:
1919
- dateTime = datetime.datetime.strptime(argstr, YYYYMMDD_FORMAT)
1916
+ dateTime = arrow.Arrow.strptime(argstr, YYYYMMDD_FORMAT)
1920
1917
  Cmd.Advance()
1921
1918
  if returnTimeStamp:
1922
1919
  return time.mktime(dateTime.timetuple())*1000
@@ -1938,7 +1935,7 @@ def getHHMM():
1938
1935
  argstr = Cmd.Current().strip().upper()
1939
1936
  if argstr:
1940
1937
  try:
1941
- datetime.datetime.strptime(argstr, HHMM_FORMAT)
1938
+ arrow.Arrow.strptime(argstr, HHMM_FORMAT)
1942
1939
  Cmd.Advance()
1943
1940
  return argstr
1944
1941
  except ValueError:
@@ -1958,7 +1955,7 @@ def getYYYYMMDD_HHMM():
1958
1955
  argstr = NEVER_DATETIME
1959
1956
  argstr = argstr.replace('T', ' ')
1960
1957
  try:
1961
- datetime.datetime.strptime(argstr, YYYYMMDD_HHMM_FORMAT)
1958
+ arrow.Arrow.strptime(argstr, YYYYMMDD_HHMM_FORMAT)
1962
1959
  Cmd.Advance()
1963
1960
  return argstr
1964
1961
  except ValueError:
@@ -1977,10 +1974,10 @@ def getDateOrDeltaFromNow(returnDateTime=False):
1977
1974
  argstr = 'TODAY'
1978
1975
  argDate = getDeltaDate(argstr)
1979
1976
  elif argstr == 'NEVER':
1980
- argDate = datetime.datetime.strptime(NEVER_DATE, YYYYMMDD_FORMAT)
1977
+ argDate = arrow.Arrow.strptime(NEVER_DATE, YYYYMMDD_FORMAT)
1981
1978
  elif YYYYMMDD_PATTERN.match(argstr):
1982
1979
  try:
1983
- argDate = datetime.datetime.strptime(argstr, YYYYMMDD_FORMAT)
1980
+ argDate = arrow.Arrow.strptime(argstr, YYYYMMDD_FORMAT)
1984
1981
  except ValueError:
1985
1982
  invalidArgumentExit(YYYYMMDD_FORMAT_REQUIRED)
1986
1983
  else:
@@ -1988,12 +1985,12 @@ def getDateOrDeltaFromNow(returnDateTime=False):
1988
1985
  Cmd.Advance()
1989
1986
  if not returnDateTime:
1990
1987
  return argDate.strftime(YYYYMMDD_FORMAT)
1991
- return (datetime.datetime(argDate.year, argDate.month, argDate.day, tzinfo=GC.Values[GC.TIMEZONE]),
1988
+ return (arrow.Arrow(argDate.year, argDate.month, argDate.day, tzinfo=GC.Values[GC.TIMEZONE]),
1992
1989
  GC.Values[GC.TIMEZONE], argDate.strftime(YYYYMMDD_FORMAT))
1993
1990
  missingArgumentExit(YYYYMMDD_FORMAT_REQUIRED)
1994
1991
 
1995
1992
  YYYYMMDDTHHMMSS_FORMAT_REQUIRED = 'yyyy-mm-ddThh:mm:ss[.fff](Z|(+|-(hh:mm)))'
1996
- TIMEZONE_FORMAT_REQUIRED = 'Z|(+|-(hh:mm))'
1993
+ TIMEZONE_FORMAT_REQUIRED = 'utc|z|local|(+|-(hh:mm))|<ValidTimezoneName>'
1997
1994
 
1998
1995
  def getTimeOrDeltaFromNow(returnDateTime=False):
1999
1996
  if Cmd.ArgumentsRemaining():
@@ -2005,7 +2002,7 @@ def getTimeOrDeltaFromNow(returnDateTime=False):
2005
2002
  argstr = NEVER_TIME
2006
2003
  elif YYYYMMDD_PATTERN.match(argstr):
2007
2004
  try:
2008
- dateTime = datetime.datetime.strptime(argstr, YYYYMMDD_FORMAT)
2005
+ dateTime = arrow.Arrow.strptime(argstr, YYYYMMDD_FORMAT)
2009
2006
  except ValueError:
2010
2007
  invalidArgumentExit(YYYYMMDD_FORMAT_REQUIRED)
2011
2008
  try:
@@ -2013,12 +2010,12 @@ def getTimeOrDeltaFromNow(returnDateTime=False):
2013
2010
  except OverflowError:
2014
2011
  pass
2015
2012
  try:
2016
- fullDateTime, tz = iso8601.parse_date(argstr)
2013
+ fullDateTime = arrow.get(argstr)
2017
2014
  Cmd.Advance()
2018
2015
  if not returnDateTime:
2019
2016
  return argstr.replace(' ', 'T')
2020
- return (fullDateTime, tz, argstr.replace(' ', 'T'))
2021
- except (iso8601.ParseError, OverflowError):
2017
+ return (fullDateTime, fullDateTime.tzinfo, argstr.replace(' ', 'T'))
2018
+ except (arrow.parser.ParserError, OverflowError):
2022
2019
  pass
2023
2020
  invalidArgumentExit(YYYYMMDDTHHMMSS_FORMAT_REQUIRED)
2024
2021
  missingArgumentExit(YYYYMMDDTHHMMSS_FORMAT_REQUIRED)
@@ -2031,19 +2028,19 @@ def getRowFilterDateOrDeltaFromNow(argstr):
2031
2028
  deltaDate = getDelta(argstr, DELTA_DATE_PATTERN)
2032
2029
  if deltaDate is None:
2033
2030
  return (False, DELTA_DATE_FORMAT_REQUIRED)
2034
- argstr = ISOformatTimeStamp(deltaDate.replace(tzinfo=iso8601.UTC))
2031
+ argstr = ISOformatTimeStamp(deltaDate.replace(tzinfo='UTC'))
2035
2032
  elif argstr == 'NEVER' or YYYYMMDD_PATTERN.match(argstr):
2036
2033
  if argstr == 'NEVER':
2037
2034
  argstr = NEVER_DATE
2038
2035
  try:
2039
- dateTime = datetime.datetime.strptime(argstr, YYYYMMDD_FORMAT)
2036
+ dateTime = arrow.Arrow.strptime(argstr, YYYYMMDD_FORMAT)
2040
2037
  except ValueError:
2041
2038
  return (False, YYYYMMDD_FORMAT_REQUIRED)
2042
- argstr = ISOformatTimeStamp(dateTime.replace(tzinfo=iso8601.UTC))
2039
+ argstr = ISOformatTimeStamp(dateTime.replace(tzinfo='UTC'))
2043
2040
  try:
2044
- iso8601.parse_date(argstr)
2041
+ arrow.get(argstr)
2045
2042
  return (True, argstr.replace(' ', 'T'))
2046
- except (iso8601.ParseError, OverflowError):
2043
+ except (arrow.parser.ParserError, OverflowError):
2047
2044
  return (False, YYYYMMDD_FORMAT_REQUIRED)
2048
2045
 
2049
2046
  def getRowFilterTimeOrDeltaFromNow(argstr):
@@ -2057,14 +2054,14 @@ def getRowFilterTimeOrDeltaFromNow(argstr):
2057
2054
  argstr = NEVER_TIME
2058
2055
  elif YYYYMMDD_PATTERN.match(argstr):
2059
2056
  try:
2060
- dateTime = datetime.datetime.strptime(argstr, YYYYMMDD_FORMAT)
2057
+ dateTime = arrow.Arrow.strptime(argstr, YYYYMMDD_FORMAT)
2061
2058
  except ValueError:
2062
2059
  return (False, YYYYMMDD_FORMAT_REQUIRED)
2063
2060
  argstr = ISOformatTimeStamp(dateTime.replace(tzinfo=GC.Values[GC.TIMEZONE]))
2064
2061
  try:
2065
- iso8601.parse_date(argstr)
2062
+ arrow.get(argstr)
2066
2063
  return (True, argstr.replace(' ', 'T'))
2067
- except (iso8601.ParseError, OverflowError):
2064
+ except (arrow.parser.ParserError, OverflowError):
2068
2065
  return (False, YYYYMMDDTHHMMSS_FORMAT_REQUIRED)
2069
2066
 
2070
2067
  def mapQueryRelativeTimes(query, keywords):
@@ -2097,9 +2094,9 @@ class StartEndTime():
2097
2094
  self.endDateTime, _, self.endTime = self._getValueOrDeltaFromNow(True)
2098
2095
  elif myarg == 'yesterday':
2099
2096
  currDate = todaysDate()
2100
- self.startDateTime = currDate+datetime.timedelta(days=-1)
2097
+ self.startDateTime = currDate.shift(days=-1)
2101
2098
  self.startTime = ISOformatTimeStamp(self.startDateTime)
2102
- self.endDateTime = currDate+datetime.timedelta(seconds=-1)
2099
+ self.endDateTime = currDate.shift(seconds=-1)
2103
2100
  self.endTime = ISOformatTimeStamp(self.endDateTime)
2104
2101
  elif myarg == 'today':
2105
2102
  currDate = todaysDate()
@@ -2114,12 +2111,12 @@ class StartEndTime():
2114
2111
  else:
2115
2112
  firstMonth = getInteger(minVal=1, maxVal=6)
2116
2113
  currDate = todaysDate()
2117
- self.startDateTime = currDate+relativedelta(months=-firstMonth, day=1, hour=0, minute=0, second=0, microsecond=0)
2114
+ self.startDateTime = currDate.shift(months=-firstMonth, day=1, hour=0, minute=0, second=0, microsecond=0)
2118
2115
  self.startTime = ISOformatTimeStamp(self.startDateTime)
2119
2116
  if myarg == 'thismonth':
2120
2117
  self.endDateTime = todaysTime()
2121
2118
  else:
2122
- self.endDateTime = currDate+relativedelta(day=1, hour=23, minute=59, second=59, microsecond=0)+relativedelta(days=-1)
2119
+ self.endDateTime = currDate.shift(day=1, hour=23, minute=59, second=59, microsecond=0).shift(days=-1)
2123
2120
  self.endTime = ISOformatTimeStamp(self.endDateTime)
2124
2121
  if self.startDateTime and self.endDateTime and self.endDateTime < self.startDateTime:
2125
2122
  Cmd.Backup()
@@ -2335,7 +2332,7 @@ def formatLocalTime(dateTimeStr):
2335
2332
  if dateTimeStr in {NEVER_TIME, NEVER_TIME_NOMS}:
2336
2333
  return GC.Values[GC.NEVER_TIME]
2337
2334
  try:
2338
- timestamp, _ = iso8601.parse_date(dateTimeStr)
2335
+ timestamp = arrow.get(dateTimeStr)
2339
2336
  if not GC.Values[GC.OUTPUT_TIMEFORMAT]:
2340
2337
  if GM.Globals[GM.CONVERT_TO_LOCAL_TIME]:
2341
2338
  return ISOformatTimeStamp(timestamp.astimezone(GC.Values[GC.TIMEZONE]))
@@ -2343,27 +2340,27 @@ def formatLocalTime(dateTimeStr):
2343
2340
  if GM.Globals[GM.CONVERT_TO_LOCAL_TIME]:
2344
2341
  return timestamp.astimezone(GC.Values[GC.TIMEZONE]).strftime(GC.Values[GC.OUTPUT_TIMEFORMAT])
2345
2342
  return timestamp.strftime(GC.Values[GC.OUTPUT_TIMEFORMAT])
2346
- except (iso8601.ParseError, OverflowError):
2343
+ except (arrow.parser.ParserError, OverflowError):
2347
2344
  return dateTimeStr
2348
2345
 
2349
2346
  def formatLocalSecondsTimestamp(timestamp):
2350
2347
  if not GC.Values[GC.OUTPUT_TIMEFORMAT]:
2351
- return ISOformatTimeStamp(datetime.datetime.fromtimestamp(int(timestamp), GC.Values[GC.TIMEZONE]))
2352
- return datetime.datetime.fromtimestamp(int(timestamp), GC.Values[GC.TIMEZONE]).strftime(GC.Values[GC.OUTPUT_TIMEFORMAT])
2348
+ return ISOformatTimeStamp(arrow.Arrow.fromtimestamp(int(timestamp), GC.Values[GC.TIMEZONE]))
2349
+ return arrow.Arrow.fromtimestamp(int(timestamp), GC.Values[GC.TIMEZONE]).strftime(GC.Values[GC.OUTPUT_TIMEFORMAT])
2353
2350
 
2354
2351
  def formatLocalTimestamp(timestamp):
2355
2352
  if not GC.Values[GC.OUTPUT_TIMEFORMAT]:
2356
- return ISOformatTimeStamp(datetime.datetime.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE]))
2357
- return datetime.datetime.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE]).strftime(GC.Values[GC.OUTPUT_TIMEFORMAT])
2353
+ return ISOformatTimeStamp(arrow.Arrow.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE]))
2354
+ return arrow.Arrow.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE]).strftime(GC.Values[GC.OUTPUT_TIMEFORMAT])
2358
2355
 
2359
2356
  def formatLocalTimestampUTC(timestamp):
2360
- return ISOformatTimeStamp(datetime.datetime.fromtimestamp(int(timestamp)//1000, iso8601.UTC))
2357
+ return ISOformatTimeStamp(arrow.Arrow.fromtimestamp(int(timestamp)//1000, 'UTC'))
2361
2358
 
2362
2359
  def formatLocalDatestamp(timestamp):
2363
2360
  try:
2364
2361
  if not GC.Values[GC.OUTPUT_DATEFORMAT]:
2365
- return datetime.datetime.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE]).strftime(YYYYMMDD_FORMAT)
2366
- return datetime.datetime.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE]).strftime(GC.Values[GC.OUTPUT_DATEFORMAT])
2362
+ return arrow.Arrow.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE]).strftime(YYYYMMDD_FORMAT)
2363
+ return arrow.Arrow.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE]).strftime(GC.Values[GC.OUTPUT_DATEFORMAT])
2367
2364
  except OverflowError:
2368
2365
  return NEVER_DATE
2369
2366
 
@@ -3707,18 +3704,18 @@ def SetGlobalVariables():
3707
3704
 
3708
3705
  def _getCfgTimezone(sectionName, itemName):
3709
3706
  value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName).lower())
3710
- if value == 'utc':
3707
+ if value in {'utc', 'z'}:
3711
3708
  GM.Globals[GM.CONVERT_TO_LOCAL_TIME] = False
3712
- return iso8601.UTC
3709
+ return arrow.now('utc').tzinfo
3713
3710
  GM.Globals[GM.CONVERT_TO_LOCAL_TIME] = True
3714
3711
  if value == 'local':
3715
- return iso8601.Local
3712
+ return arrow.now(value).tzinfo
3716
3713
  try:
3717
- return iso8601.parse_timezone_str(value)
3718
- except (iso8601.ParseError, OverflowError):
3714
+ return arrow.now(value).tzinfo
3715
+ except (arrow.parser.ParserError, OverflowError):
3719
3716
  _printValueError(sectionName, itemName, value, f'{Msg.EXPECTED}: {TIMEZONE_FORMAT_REQUIRED}')
3720
3717
  GM.Globals[GM.CONVERT_TO_LOCAL_TIME] = False
3721
- return iso8601.UTC
3718
+ return arrow.now('utc').tzinfo
3722
3719
 
3723
3720
  def _getCfgDirectory(sectionName, itemName):
3724
3721
  dirPath = os.path.expanduser(_stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)))
@@ -3736,10 +3733,7 @@ def SetGlobalVariables():
3736
3733
  if value and not os.path.isabs(value):
3737
3734
  value = os.path.expanduser(os.path.join(_getCfgDirectory(sectionName, GC.CONFIG_DIR), value))
3738
3735
  elif not value and itemName == GC.CACERTS_PEM:
3739
- if hasattr(sys, '_MEIPASS'):
3740
- value = os.path.join(sys._MEIPASS, GC.FN_CACERTS_PEM) #pylint: disable=no-member
3741
- else:
3742
- value = os.path.join(GM.Globals[GM.GAM_PATH], GC.FN_CACERTS_PEM)
3736
+ value = os.path.join(GM.Globals[GM.GAM_PATH], GC.FN_CACERTS_PEM)
3743
3737
  return value
3744
3738
 
3745
3739
  def _readGamCfgFile(config, fileName):
@@ -4047,7 +4041,7 @@ def SetGlobalVariables():
4047
4041
  GC.Values[itemName] = _getCfgDirectory(sectionName, itemName)
4048
4042
  elif varType == GC.TYPE_TIMEZONE:
4049
4043
  GC.Values[itemName] = _getCfgTimezone(sectionName, itemName)
4050
- GM.Globals[GM.DATETIME_NOW] = datetime.datetime.now(GC.Values[GC.TIMEZONE])
4044
+ GM.Globals[GM.DATETIME_NOW] = arrow.now(GC.Values[GC.TIMEZONE])
4051
4045
  # Everything else except row filters
4052
4046
  for itemName, itemEntry in sorted(GC.VAR_INFO.items()):
4053
4047
  varType = itemEntry[GC.VAR_TYPE]
@@ -4393,12 +4387,11 @@ _DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds
4393
4387
  class signjwtJWTCredentials(google.auth.jwt.Credentials):
4394
4388
  ''' Class used for DASA '''
4395
4389
  def _make_jwt(self):
4396
- now = datetime.datetime.utcnow()
4397
- lifetime = datetime.timedelta(seconds=self._token_lifetime)
4398
- expiry = now + lifetime
4390
+ now = arrow.utcnow()
4391
+ expiry = now.shift(seconds=self._token_lifetime)
4399
4392
  payload = {
4400
- "iat": google.auth._helpers.datetime_to_secs(now),
4401
- "exp": google.auth._helpers.datetime_to_secs(expiry),
4393
+ "iat": now.int_timestamp,
4394
+ "exp": expiry.int_timestamp,
4402
4395
  "iss": self._issuer,
4403
4396
  "sub": self._subject,
4404
4397
  }
@@ -4406,7 +4399,7 @@ class signjwtJWTCredentials(google.auth.jwt.Credentials):
4406
4399
  payload["aud"] = self._audience
4407
4400
  payload.update(self._additional_claims)
4408
4401
  jwt = self._signer.sign(payload)
4409
- return jwt, expiry
4402
+ return jwt, expiry.naive
4410
4403
 
4411
4404
  # Some Workforce Identity Federation endpoints such as GitHub Actions
4412
4405
  # only allow TLS 1.2 as of April 2023.
@@ -4419,15 +4412,14 @@ class signjwtCredentials(google.oauth2.service_account.Credentials):
4419
4412
  ''' Class used for DwD '''
4420
4413
 
4421
4414
  def _make_authorization_grant_assertion(self):
4422
- now = datetime.datetime.utcnow()
4423
- lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS)
4424
- expiry = now + lifetime
4415
+ now = arrow.utcnow()
4416
+ expiry = now.shift(seconds=_DEFAULT_TOKEN_LIFETIME_SECS)
4425
4417
  payload = {
4426
- "iat": google.auth._helpers.datetime_to_secs(now),
4427
- "exp": google.auth._helpers.datetime_to_secs(expiry),
4428
- "iss": self._service_account_email,
4429
- "aud": API.GOOGLE_OAUTH2_TOKEN_ENDPOINT,
4430
- "scope": google.auth._helpers.scopes_to_string(self._scopes or ()),
4418
+ "iat": now.int_timestamp,
4419
+ "exp": expiry.int_timestamp,
4420
+ "iss": self._service_account_email,
4421
+ "aud": API.GOOGLE_OAUTH2_TOKEN_ENDPOINT,
4422
+ "scope": google.auth._helpers.scopes_to_string(self._scopes or ()),
4431
4423
  }
4432
4424
  payload.update(self._additional_claims)
4433
4425
  # The subject can be a user email for domain-wide delegation.
@@ -4541,7 +4533,7 @@ def getOauth2TxtCredentials(exitOnError=True, api=None, noDASA=False, refreshOnl
4541
4533
  creds.token = jsonDict['access_token']
4542
4534
  creds._id_token = jsonDict['id_token_jwt']
4543
4535
  GM.Globals[GM.DECODED_ID_TOKEN] = jsonDict['id_token']
4544
- creds.expiry = datetime.datetime.strptime(token_expiry, YYYYMMDDTHHMMSSZ_FORMAT)
4536
+ creds.expiry = arrow.Arrow.strptime(token_expiry, YYYYMMDDTHHMMSSZ_FORMAT, tzinfo='UTC').naive
4545
4537
  return (not noScopes, creds)
4546
4538
  if jsonDict and exitOnError:
4547
4539
  invalidOauth2TxtExit(Msg.INVALID)
@@ -7431,15 +7423,15 @@ def RowFilterMatch(row, titlesList, rowFilter, rowFilterModeAll, rowDropFilter,
7431
7423
  def stripTimeFromDateTime(rowDate):
7432
7424
  if YYYYMMDD_PATTERN.match(rowDate):
7433
7425
  try:
7434
- rowTime = datetime.datetime.strptime(rowDate, YYYYMMDD_FORMAT)
7426
+ rowTime = arrow.Arrow.strptime(rowDate, YYYYMMDD_FORMAT)
7435
7427
  except ValueError:
7436
7428
  return None
7437
7429
  else:
7438
7430
  try:
7439
- rowTime, _ = iso8601.parse_date(rowDate)
7440
- except (iso8601.ParseError, OverflowError):
7431
+ rowTime = arrow.get(rowDate)
7432
+ except (arrow.parser.ParserError, OverflowError):
7441
7433
  return None
7442
- return ISOformatTimeStamp(datetime.datetime(rowTime.year, rowTime.month, rowTime.day, tzinfo=iso8601.UTC))
7434
+ return ISOformatTimeStamp(arrow.Arrow(rowTime.year, rowTime.month, rowTime.day, tzinfo='UTC'))
7443
7435
 
7444
7436
  def rowDateTimeFilterMatch(dateMode, op, filterDate):
7445
7437
  def checkMatch(rowDate):
@@ -7501,8 +7493,8 @@ def RowFilterMatch(row, titlesList, rowFilter, rowFilterModeAll, rowDropFilter,
7501
7493
  if YYYYMMDD_PATTERN.match(rowDate):
7502
7494
  return None
7503
7495
  try:
7504
- rowTime, _ = iso8601.parse_date(rowDate)
7505
- except (iso8601.ParseError, OverflowError):
7496
+ rowTime = arrow.get(rowDate)
7497
+ except (arrow.parser.ParserError, OverflowError):
7506
7498
  return None
7507
7499
  return f'{rowTime.hour:02d}:{rowTime.minute:02d}'
7508
7500
 
@@ -8703,10 +8695,10 @@ class CSVPrintFile():
8703
8695
  sheetTitle = self.todrive['sheetEntity']['sheetTitle']
8704
8696
  else:
8705
8697
  sheetTitle = self.todrive['sheettitle']
8706
- tdbasetime = tdtime = datetime.datetime.now(GC.Values[GC.TIMEZONE])
8698
+ tdbasetime = tdtime = arrow.now(GC.Values[GC.TIMEZONE])
8707
8699
  if self.todrive['daysoffset'] is not None or self.todrive['hoursoffset'] is not None:
8708
- tdtime = tdbasetime+relativedelta(days=-self.todrive['daysoffset'] if self.todrive['daysoffset'] is not None else 0,
8709
- hours=-self.todrive['hoursoffset'] if self.todrive['hoursoffset'] is not None else 0)
8700
+ tdtime = tdbasetime.shift(days=-self.todrive['daysoffset'] if self.todrive['daysoffset'] is not None else 0,
8701
+ hours=-self.todrive['hoursoffset'] if self.todrive['hoursoffset'] is not None else 0)
8710
8702
  if self.todrive['timestamp']:
8711
8703
  if title:
8712
8704
  title += ' - '
@@ -8716,8 +8708,8 @@ class CSVPrintFile():
8716
8708
  title += tdtime.strftime(self.todrive['timeformat'])
8717
8709
  if self.todrive['sheettimestamp']:
8718
8710
  if self.todrive['sheetdaysoffset'] is not None or self.todrive['sheethoursoffset'] is not None:
8719
- tdtime = tdbasetime+relativedelta(days=-self.todrive['sheetdaysoffset'] if self.todrive['sheetdaysoffset'] is not None else 0,
8720
- hours=-self.todrive['sheethoursoffset'] if self.todrive['sheethoursoffset'] is not None else 0)
8711
+ tdtime = tdbasetime.shift(days=-self.todrive['sheetdaysoffset'] if self.todrive['sheetdaysoffset'] is not None else 0,
8712
+ hours=-self.todrive['sheethoursoffset'] if self.todrive['sheethoursoffset'] is not None else 0)
8721
8713
  if sheetTitle:
8722
8714
  sheetTitle += ' - '
8723
8715
  if not self.todrive['sheettimeformat']:
@@ -9306,7 +9298,7 @@ def getLocalGoogleTimeOffset(testLocation=GOOGLE_TIMECHECK_LOCATION):
9306
9298
  for prot in ['http', 'https']:
9307
9299
  try:
9308
9300
  headerData = httpObj.request(f'{prot}://'+testLocation, 'HEAD')
9309
- googleUTC = datetime.datetime.strptime(headerData[0]['date'], '%a, %d %b %Y %H:%M:%S %Z').replace(tzinfo=iso8601.UTC)
9301
+ googleUTC = arrow.Arrow.strptime(headerData[0]['date'], '%a, %d %b %Y %H:%M:%S %Z', tzinfo='UTC')
9310
9302
  except (httplib2.HttpLib2Error, RuntimeError) as e:
9311
9303
  handleServerError(e)
9312
9304
  except httplib2.socks.HTTPError as e:
@@ -9319,7 +9311,7 @@ def getLocalGoogleTimeOffset(testLocation=GOOGLE_TIMECHECK_LOCATION):
9319
9311
  if prot == 'http':
9320
9312
  continue
9321
9313
  systemErrorExit(NETWORK_ERROR_RC, Msg.INVALID_HTTP_HEADER.format(str(headerData)))
9322
- offset = remainder = int(abs((datetime.datetime.now(iso8601.UTC)-googleUTC).total_seconds()))
9314
+ offset = remainder = int(abs((arrow.utcnow()-googleUTC).total_seconds()))
9323
9315
  if offset < MAX_LOCAL_GOOGLE_TIME_OFFSET and prot == 'http':
9324
9316
  continue
9325
9317
  timeoff = []
@@ -11033,7 +11025,7 @@ class Credentials(google.oauth2.credentials.Credentials):
11033
11025
  expiry = info.get('token_expiry')
11034
11026
  if expiry:
11035
11027
  # Convert the raw expiry to datetime
11036
- expiry = datetime.datetime.strptime(expiry, YYYYMMDDTHHMMSSZ_FORMAT)
11028
+ expiry = arrow.Arrow.strptime(expiry, YYYYMMDDTHHMMSSZ_FORMAT)
11037
11029
  id_token_data = info.get('decoded_id_token')
11038
11030
 
11039
11031
  # Provide backwards compatibility with field names when loading from JSON.
@@ -11297,7 +11289,7 @@ def doOAuthInfo():
11297
11289
  if 'email' in token_info:
11298
11290
  printKeyValueList(['Google Workspace Admin', f'{token_info["email"]}'])
11299
11291
  if 'expires_in' in token_info:
11300
- printKeyValueList(['Expires', ISOformatTimeStamp((datetime.datetime.now()+datetime.timedelta(seconds=token_info['expires_in'])).replace(tzinfo=GC.Values[GC.TIMEZONE]))])
11292
+ printKeyValueList(['Expires', ISOformatTimeStamp(arrow.now(GC.Values[GC.TIMEZONE]).shift(seconds=token_info['expires_in']))])
11301
11293
  if showDetails:
11302
11294
  for k, v in sorted(token_info.items()):
11303
11295
  if k not in ['email', 'expires_in', 'issued_to', 'scope']:
@@ -12413,7 +12405,7 @@ def checkServiceAccount(users):
12413
12405
  throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID, GAPI.NOT_FOUND,
12414
12406
  GAPI.PERMISSION_DENIED, GAPI.SERVICE_NOT_AVAILABLE],
12415
12407
  name=name, fields='validAfterTime')
12416
- key_created, _ = iso8601.parse_date(key['validAfterTime'])
12408
+ key_created = arrow.get(key['validAfterTime'])
12417
12409
  key_age = todaysTime()-key_created
12418
12410
  printPassFail(Msg.SERVICE_ACCOUNT_PRIVATE_KEY_AGE.format(key_age.days), testWarn if key_age.days > 30 else testPass)
12419
12411
  except GAPI.permissionDenied:
@@ -12668,15 +12660,15 @@ def _generatePrivateKeyAndPublicCert(projectId, clientEmail, name, key_size, b64
12668
12660
  _validate=False)]))
12669
12661
  # Gooogle seems to enforce the not before date strictly. Set the not before
12670
12662
  # date to be UTC two minutes ago which should cover any clock skew.
12671
- now = datetime.datetime.utcnow()
12672
- builder = builder.not_valid_before(now - datetime.timedelta(minutes=2))
12663
+ now = arrow.utcnow()
12664
+ builder = builder.not_valid_before(now.shift(minutes=-2).naive)
12673
12665
  # Google defaults to 12/31/9999 date for end time if there's no
12674
12666
  # policy to restrict key age
12675
12667
  if validityHours:
12676
- expires = now + datetime.timedelta(hours=validityHours) - datetime.timedelta(minutes=2)
12668
+ expires = now.shift(hours=validityHours, minutes=-2).naive
12677
12669
  builder = builder.not_valid_after(expires)
12678
12670
  else:
12679
- builder = builder.not_valid_after(datetime.datetime(9999, 12, 31, 23, 59))
12671
+ builder = builder.not_valid_after(arrow.Arrow(9999, 12, 31, 23, 59).naive)
12680
12672
  builder = builder.serial_number(x509.random_serial_number())
12681
12673
  builder = builder.public_key(public_key)
12682
12674
  builder = builder.add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True)
@@ -13053,7 +13045,7 @@ def _showMailboxMonitorRequestStatus(request, i=0, count=0):
13053
13045
  def doCreateMonitor():
13054
13046
  auditObject, parameters = getAuditParameters(emailAddressRequired=True, requestIdRequired=False, destUserRequired=True)
13055
13047
  #end_date defaults to 30 days in the future...
13056
- end_date = (GM.Globals[GM.DATETIME_NOW]+datetime.timedelta(days=30)).strftime(YYYYMMDD_HHMM_FORMAT)
13048
+ end_date = GM.Globals[GM.DATETIME_NOW].shift(days=30).strftime(YYYYMMDD_HHMM_FORMAT)
13057
13049
  begin_date = None
13058
13050
  incoming_headers_only = outgoing_headers_only = drafts_headers_only = chats_headers_only = False
13059
13051
  drafts = chats = True
@@ -13226,7 +13218,7 @@ def _adjustTryDate(errMsg, numDateChanges, limitDateChanges, prevTryDate):
13226
13218
  else:
13227
13219
  match_date = re.match('End date greater than LastReportedDate.', errMsg)
13228
13220
  if match_date:
13229
- tryDateTime = datetime.datetime.strptime(prevTryDate, YYYYMMDD_FORMAT)-datetime.timedelta(days=1)
13221
+ tryDateTime = arrow.Arrow.strptime(prevTryDate, YYYYMMDD_FORMAT).shift(days=-1)
13230
13222
  tryDate = tryDateTime.strftime(YYYYMMDD_FORMAT)
13231
13223
  if (not match_date) or (numDateChanges > limitDateChanges >= 0):
13232
13224
  printWarningMessage(DATA_NOT_AVALIABLE_RC, errMsg)
@@ -13237,18 +13229,17 @@ def _checkDataRequiredServices(result, tryDate, dataRequiredServices, parameterS
13237
13229
  # -1: Data not available:
13238
13230
  # 0: Backup to earlier date
13239
13231
  # 1: Data available
13240
- oneDay = datetime.timedelta(days=1)
13241
13232
  dataWarnings = result.get('warnings', [])
13242
13233
  usageReports = result.get('usageReports', [])
13243
13234
  # move to day before if we don't have at least one usageReport with parameters
13244
13235
  if not usageReports or not usageReports[0].get('parameters', []):
13245
- tryDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)-oneDay
13236
+ tryDateTime = arrow.Arrow.strptime(tryDate, YYYYMMDD_FORMAT).shift(days=-1)
13246
13237
  return (0, tryDateTime.strftime(YYYYMMDD_FORMAT), None)
13247
13238
  for warning in dataWarnings:
13248
13239
  if warning['code'] == 'PARTIAL_DATA_AVAILABLE':
13249
13240
  for app in warning['data']:
13250
13241
  if app['key'] == 'application' and app['value'] != 'docs' and app['value'] in dataRequiredServices:
13251
- tryDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)-oneDay
13242
+ tryDateTime = arrow.Arrow.strptime(tryDate, YYYYMMDD_FORMAT).shift(days=-1)
13252
13243
  return (0, tryDateTime.strftime(YYYYMMDD_FORMAT), None)
13253
13244
  elif warning['code'] == 'DATA_NOT_AVAILABLE':
13254
13245
  for app in warning['data']:
@@ -13265,11 +13256,11 @@ def _checkDataRequiredServices(result, tryDate, dataRequiredServices, parameterS
13265
13256
  if not requiredServices:
13266
13257
  break
13267
13258
  else:
13268
- tryDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)-oneDay
13259
+ tryDateTime = arrow.Arrow.strptime(tryDate, YYYYMMDD_FORMAT).shift(days=-1)
13269
13260
  return (0, tryDateTime.strftime(YYYYMMDD_FORMAT), None)
13270
13261
  if checkUserEmail:
13271
13262
  if 'entity' not in usageReports[0] or 'userEmail' not in usageReports[0]['entity']:
13272
- tryDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)-oneDay
13263
+ tryDateTime = arrow.Arrow.strptime(tryDate, YYYYMMDD_FORMAT).shift(days=-1)
13273
13264
  return (0, tryDateTime.strftime(YYYYMMDD_FORMAT), None)
13274
13265
  return (1, tryDate, usageReports)
13275
13266
 
@@ -13383,11 +13374,13 @@ REPORTS_PARAMETERS_SIMPLE_TYPES = ['intValue', 'boolValue', 'datetimeValue', 'st
13383
13374
  # [(user all|<UserItem>)|(orgunit|org|ou <OrgUnitPath> [showorgunit])|(select <UserTypeEntity>)]
13384
13375
  # [([start|startdate <Date>] [end|enddate <Date>])|(range <Date> <Date>)|
13385
13376
  # thismonth|(previousmonths <Integer>)]
13377
+ # [skipdates <Date>[:<Date>](,<Date>[:<Date>])*] [skipdaysofweek <DayOfWeek>(,<DayOfWeek>)*]
13386
13378
  # [fields|parameters <String>)]
13387
13379
  # [convertmbtogb]
13388
13380
  # gam report usage customer [todrive <ToDriveAttribute>*]
13389
13381
  # [([start|startdate <Date>] [end|enddate <Date>])|(range <Date> <Date>)|
13390
13382
  # thismonth|(previousmonths <Integer>)]
13383
+ # [skipdates <Date>[:<Date>](,<Date>[:<Date>])*] [skipdaysofweek <DayOfWeek>(,<DayOfWeek>)*]
13391
13384
  # [fields|parameters <String>)]
13392
13385
  # [convertmbtogb]
13393
13386
  def doReportUsage():
@@ -13409,8 +13402,8 @@ def doReportUsage():
13409
13402
  invalidArgumentExit(DELTA_DATE_FORMAT_REQUIRED)
13410
13403
  return deltaDate
13411
13404
  try:
13412
- argDate = datetime.datetime.strptime(argstr, YYYYMMDD_FORMAT)
13413
- return datetime.datetime(argDate.year, argDate.month, argDate.day, tzinfo=GC.Values[GC.TIMEZONE])
13405
+ argDate = arrow.Arrow.strptime(argstr, YYYYMMDD_FORMAT)
13406
+ return arrow.Arrow(argDate.year, argDate.month, argDate.day, tzinfo=GC.Values[GC.TIMEZONE])
13414
13407
  except ValueError:
13415
13408
  Cmd.Backup()
13416
13409
  invalidArgumentExit(YYYYMMDD_FORMAT_REQUIRED)
@@ -13441,7 +13434,6 @@ def doReportUsage():
13441
13434
  startEndTime = StartEndTime('startdate', 'enddate', 'date')
13442
13435
  skipDayNumbers = []
13443
13436
  skipDates = set()
13444
- oneDay = datetime.timedelta(days=1)
13445
13437
  while Cmd.ArgumentsRemaining():
13446
13438
  myarg = getArgument()
13447
13439
  if csvPF and myarg == 'todrive':
@@ -13479,10 +13471,10 @@ def doReportUsage():
13479
13471
  usageErrorExit(Msg.INVALID_DATE_TIME_RANGE.format(myarg, skipEnd, myarg, skipStart))
13480
13472
  while skipStartDate <= skipEndDate:
13481
13473
  skipDates.add(skipStartDate)
13482
- skipStartDate += oneDay
13474
+ skipStartDate = skipStartDate.shift(days=1)
13483
13475
  elif myarg == 'skipdaysofweek':
13484
- skipdaynames = getString(Cmd.OB_STRING).split(',')
13485
- dow = [d.lower() for d in calendarlib.day_abbr]
13476
+ skipdaynames = getString(Cmd.OB_STRING).lower().split(',')
13477
+ dow = [d.lower() for d in DAYS_OF_WEEK]
13486
13478
  skipDayNumbers = [dow.index(d) for d in skipdaynames if d in dow]
13487
13479
  elif userReports and myarg == 'user':
13488
13480
  userKey = getString(Cmd.OB_EMAIL_ADDRESS)
@@ -13501,7 +13493,7 @@ def doReportUsage():
13501
13493
  if startEndTime.endDateTime is None:
13502
13494
  startEndTime.endDateTime = todaysDate()
13503
13495
  if startEndTime.startDateTime is None:
13504
- startEndTime.startDateTime = startEndTime.endDateTime+datetime.timedelta(days=-30)
13496
+ startEndTime.startDateTime = startEndTime.endDateTime.shift(days=-30)
13505
13497
  startDateTime = startEndTime.startDateTime
13506
13498
  startDate = startDateTime.strftime(YYYYMMDD_FORMAT)
13507
13499
  endDateTime = startEndTime.endDateTime
@@ -13534,10 +13526,10 @@ def doReportUsage():
13534
13526
  parameters = ','.join(parameters) if parameters else None
13535
13527
  while startDateTime <= endDateTime:
13536
13528
  if startDateTime.weekday() in skipDayNumbers or startDateTime in skipDates:
13537
- startDateTime += oneDay
13529
+ startDateTime = startDateTime.shift(days=1)
13538
13530
  continue
13539
13531
  useDate = startDateTime.strftime(YYYYMMDD_FORMAT)
13540
- startDateTime += oneDay
13532
+ startDateTime = startDateTime.shift(days=1)
13541
13533
  try:
13542
13534
  for kwarg in kwargs:
13543
13535
  if userReports:
@@ -13728,7 +13720,7 @@ def doReport():
13728
13720
  mg = DISABLED_REASON_TIME_PATTERN.match(item['stringValue'])
13729
13721
  if mg:
13730
13722
  try:
13731
- disabledTime = formatLocalTime(datetime.datetime.strptime(mg.group(1), '%Y/%m/%d-%H:%M:%S').replace(tzinfo=iso8601.UTC).strftime(YYYYMMDDTHHMMSSZ_FORMAT))
13723
+ disabledTime = formatLocalTime(arrow.Arrow.strptime(mg.group(1), '%Y/%m/%d-%H:%M:%S').replace(tzinfo='UTC').strftime(YYYYMMDDTHHMMSSZ_FORMAT))
13732
13724
  row['accounts:disabled_time'] = disabledTime
13733
13725
  csvPF.AddTitles('accounts:disabled_time')
13734
13726
  except ValueError:
@@ -13963,7 +13955,6 @@ def doReport():
13963
13955
  eventCounts = {}
13964
13956
  eventNames = []
13965
13957
  startEndTime = StartEndTime('start', 'end')
13966
- oneDay = datetime.timedelta(days=1)
13967
13958
  filterTimes = {}
13968
13959
  maxActivities = maxEvents = 0
13969
13960
  maxResults = 1000
@@ -14175,7 +14166,7 @@ def doReport():
14175
14166
  if fullData == 0:
14176
14167
  if numDateChanges > limitDateChanges >= 0:
14177
14168
  break
14178
- startDateTime = endDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)
14169
+ startDateTime = endDateTime = arrow.Arrow.strptime(tryDate, YYYYMMDD_FORMAT)
14179
14170
  continue
14180
14171
  if not select and userKey == 'all':
14181
14172
  pageMessage = getPageMessageForWhom(forWhom, showDate=tryDate)
@@ -14204,7 +14195,7 @@ def doReport():
14204
14195
  tryDate = _adjustTryDate(str(e), numDateChanges, limitDateChanges, tryDate)
14205
14196
  if not tryDate:
14206
14197
  break
14207
- startDateTime = endDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)
14198
+ startDateTime = endDateTime = arrow.Arrow.strptime(tryDate, YYYYMMDD_FORMAT)
14208
14199
  continue
14209
14200
  except GAPI.invalidInput as e:
14210
14201
  systemErrorExit(GOOGLE_API_ERROR_RC, str(e))
@@ -14217,7 +14208,7 @@ def doReport():
14217
14208
  break
14218
14209
  except GAPI.forbidden as e:
14219
14210
  accessErrorExit(None, str(e))
14220
- startDateTime += oneDay
14211
+ startDateTime = startDateTime.shift(days=1)
14221
14212
  if exitUserLoop:
14222
14213
  break
14223
14214
  if user != 'all' and lastDate is None and GC.Values[GC.CSV_OUTPUT_USERS_AUDIT]:
@@ -14274,7 +14265,7 @@ def doReport():
14274
14265
  if fullData == 0:
14275
14266
  if numDateChanges > limitDateChanges >= 0:
14276
14267
  break
14277
- startDateTime = endDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)
14268
+ startDateTime = endDateTime = arrow.Arrow.strptime(tryDate, YYYYMMDD_FORMAT)
14278
14269
  continue
14279
14270
  usage = callGAPIpages(service, 'get', 'usageReports',
14280
14271
  throwReasons=[GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.FORBIDDEN],
@@ -14292,13 +14283,13 @@ def doReport():
14292
14283
  tryDate = _adjustTryDate(str(e), numDateChanges, limitDateChanges, tryDate)
14293
14284
  if not tryDate:
14294
14285
  break
14295
- startDateTime = endDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)
14286
+ startDateTime = endDateTime = arrow.Arrow.strptime(tryDate, YYYYMMDD_FORMAT)
14296
14287
  continue
14297
14288
  except GAPI.invalidInput as e:
14298
14289
  systemErrorExit(GOOGLE_API_ERROR_RC, str(e))
14299
14290
  except GAPI.forbidden as e:
14300
14291
  accessErrorExit(None, str(e))
14301
- startDateTime += oneDay
14292
+ startDateTime = startDateTime.shift(days=1)
14302
14293
  csvPF.writeCSVfile(f'Customer Report - {tryDate}')
14303
14294
  else: # activityReports
14304
14295
  csvPF.SetTitles('name')
@@ -14368,8 +14359,8 @@ def doReport():
14368
14359
  eventTime = activity.get('id', {}).get('time', UNKNOWN)
14369
14360
  if eventTime != UNKNOWN:
14370
14361
  try:
14371
- eventTime, _ = iso8601.parse_date(eventTime)
14372
- except (iso8601.ParseError, OverflowError):
14362
+ eventTime = arrow.get(eventTime)
14363
+ except (arrow.parser.ParserError, OverflowError):
14373
14364
  eventTime = UNKNOWN
14374
14365
  if eventTime != UNKNOWN:
14375
14366
  eventDate = eventTime.strftime(YYYYMMDD_FORMAT)
@@ -14393,7 +14384,7 @@ def doReport():
14393
14384
  if val is not None:
14394
14385
  val = int(val)
14395
14386
  if val >= 62135683200:
14396
- event[item['name']] = ISOformatTimeStamp(datetime.datetime.fromtimestamp(val-62135683200, GC.Values[GC.TIMEZONE]))
14387
+ event[item['name']] = ISOformatTimeStamp(arrow.Arrow.fromtimestamp(val-62135683200, GC.Values[GC.TIMEZONE]))
14397
14388
  else:
14398
14389
  event[item['name']] = val
14399
14390
  else:
@@ -23848,7 +23839,7 @@ def _filterActiveTimeRanges(cros, selected, listLimit, startDate, endDate, activ
23848
23839
  activeTimeRanges.reverse()
23849
23840
  i = 0
23850
23841
  for item in activeTimeRanges:
23851
- activityDate = datetime.datetime.strptime(item['date'], YYYYMMDD_FORMAT)
23842
+ activityDate = arrow.Arrow.strptime(item['date'], YYYYMMDD_FORMAT)
23852
23843
  if ((startDate is None) or (activityDate >= startDate)) and ((endDate is None) or (activityDate <= endDate)):
23853
23844
  item['duration'] = formatMilliSeconds(item['activeTime'])
23854
23845
  item['minutes'] = item['activeTime']//60000
@@ -23867,7 +23858,7 @@ def _filterDeviceFiles(cros, selected, listLimit, startTime, endTime):
23867
23858
  filteredItems = []
23868
23859
  i = 0
23869
23860
  for item in cros.get('deviceFiles', []):
23870
- timeValue, _ = iso8601.parse_date(item['createTime'])
23861
+ timeValue = arrow.get(item['createTime'])
23871
23862
  if ((startTime is None) or (timeValue >= startTime)) and ((endTime is None) or (timeValue <= endTime)):
23872
23863
  item['createTime'] = formatLocalTime(item['createTime'])
23873
23864
  filteredItems.append(item)
@@ -23884,7 +23875,7 @@ def _filterCPUStatusReports(cros, selected, listLimit, startTime, endTime):
23884
23875
  filteredItems = []
23885
23876
  i = 0
23886
23877
  for item in cros.get('cpuStatusReports', []):
23887
- timeValue, _ = iso8601.parse_date(item['reportTime'])
23878
+ timeValue = arrow.get(item['reportTime'])
23888
23879
  if ((startTime is None) or (timeValue >= startTime)) and ((endTime is None) or (timeValue <= endTime)):
23889
23880
  item['reportTime'] = formatLocalTime(item['reportTime'])
23890
23881
  for tempInfo in item.get('cpuTemperatureInfo', []):
@@ -23905,7 +23896,7 @@ def _filterSystemRamFreeReports(cros, selected, listLimit, startTime, endTime):
23905
23896
  filteredItems = []
23906
23897
  i = 0
23907
23898
  for item in cros.get('systemRamFreeReports', []):
23908
- timeValue, _ = iso8601.parse_date(item['reportTime'])
23899
+ timeValue = arrow.get(item['reportTime'])
23909
23900
  if ((startTime is None) or (timeValue >= startTime)) and ((endTime is None) or (timeValue <= endTime)):
23910
23901
  item['reportTime'] = formatLocalTime(item['reportTime'])
23911
23902
  item['systemRamFreeInfo'] = ','.join([str(x) for x in item['systemRamFreeInfo']])
@@ -23938,7 +23929,7 @@ def _filterScreenshotFiles(cros, selected, listLimit, startTime, endTime):
23938
23929
  filteredItems = []
23939
23930
  i = 0
23940
23931
  for item in cros.get('screenshotFiles', []):
23941
- timeValue, _ = iso8601.parse_date(item['createTime'])
23932
+ timeValue = arrow.get(item['createTime'])
23942
23933
  if ((startTime is None) or (timeValue >= startTime)) and ((endTime is None) or (timeValue <= endTime)):
23943
23934
  item['createTime'] = formatLocalTime(item['createTime'])
23944
23935
  filteredItems.append(item)
@@ -23975,7 +23966,7 @@ def _computeDVRstorageFreePercentage(cros):
23975
23966
 
23976
23967
  def _getFilterDateTime():
23977
23968
  filterDate = getYYYYMMDD(returnDateTime=True)
23978
- return (filterDate, filterDate.replace(tzinfo=iso8601.UTC))
23969
+ return (filterDate, filterDate.replace(tzinfo='UTC'))
23979
23970
 
23980
23971
  CROS_FIELDS_CHOICE_MAP = {
23981
23972
  'activetimeranges': ['activeTimeRanges.activeTime', 'activeTimeRanges.date'],
@@ -24386,9 +24377,9 @@ def getDeviceFilesEntity():
24386
24377
  else:
24387
24378
  for timeItem in myarg.split(','):
24388
24379
  try:
24389
- timestamp, _ = iso8601.parse_date(timeItem)
24380
+ timestamp = arrow.get(timeItem)
24390
24381
  deviceFilesEntity['list'].append(ISOformatTimeStamp(timestamp.astimezone(GC.Values[GC.TIMEZONE])))
24391
- except (iso8601.ParseError, OverflowError):
24382
+ except (arrow.parser.ParserError, OverflowError):
24392
24383
  Cmd.Backup()
24393
24384
  invalidArgumentExit(YYYYMMDDTHHMMSS_FORMAT_REQUIRED)
24394
24385
  return deviceFilesEntity
@@ -24415,14 +24406,14 @@ def _selectDeviceFiles(deviceId, deviceFiles, deviceFilesEntity):
24415
24406
  count = 0
24416
24407
  if deviceFilesEntity['time'][0] == 'before':
24417
24408
  for deviceFile in deviceFiles:
24418
- createTime, _ = iso8601.parse_date(deviceFile['createTime'])
24409
+ createTime = arrow.get(deviceFile['createTime'])
24419
24410
  if createTime >= dateTime:
24420
24411
  break
24421
24412
  count += 1
24422
24413
  return deviceFiles[:count]
24423
24414
  # if deviceFilesEntity['time'][0] == 'after':
24424
24415
  for deviceFile in deviceFiles:
24425
- createTime, _ = iso8601.parse_date(deviceFile['createTime'])
24416
+ createTime = arrow.get(deviceFile['createTime'])
24426
24417
  if createTime >= dateTime:
24427
24418
  break
24428
24419
  count += 1
@@ -24431,14 +24422,14 @@ def _selectDeviceFiles(deviceId, deviceFiles, deviceFilesEntity):
24431
24422
  dateTime = deviceFilesEntity['range'][1]
24432
24423
  spos = 0
24433
24424
  for deviceFile in deviceFiles:
24434
- createTime, _ = iso8601.parse_date(deviceFile['createTime'])
24425
+ createTime = arrow.get(deviceFile['createTime'])
24435
24426
  if createTime >= dateTime:
24436
24427
  break
24437
24428
  spos += 1
24438
24429
  dateTime = deviceFilesEntity['range'][2]
24439
24430
  epos = spos
24440
24431
  for deviceFile in deviceFiles[spos:]:
24441
- createTime, _ = iso8601.parse_date(deviceFile['createTime'])
24432
+ createTime = arrow.get(deviceFile['createTime'])
24442
24433
  if createTime >= dateTime:
24443
24434
  break
24444
24435
  epos += 1
@@ -25221,7 +25212,7 @@ def doInfoPrintShowCrOSTelemetry():
25221
25212
  i = 0
25222
25213
  for item in listItems:
25223
25214
  if 'reportTime' in item:
25224
- timeValue, _ = iso8601.parse_date(item['reportTime'])
25215
+ timeValue = arrow.get(item['reportTime'])
25225
25216
  else:
25226
25217
  timeValue = None
25227
25218
  if (timeValue is None) or (((startTime is None) or (timeValue >= startTime)) and ((endTime is None) or (timeValue <= endTime))):
@@ -40062,15 +40053,15 @@ def _getEventDaysOfWeek(event):
40062
40053
  if attr in event:
40063
40054
  if 'date' in event[attr]:
40064
40055
  try:
40065
- dateTime = datetime.datetime.strptime(event[attr]['date'], YYYYMMDD_FORMAT)
40066
- event[attr]['dayOfWeek'] = calendarlib.day_abbr[dateTime.weekday()]
40056
+ dateTime = arrow.Arrow.strptime(event[attr]['date'], YYYYMMDD_FORMAT)
40057
+ event[attr]['dayOfWeek'] = DAYS_OF_WEEK[dateTime.weekday()]
40067
40058
  except ValueError:
40068
40059
  pass
40069
40060
  elif 'dateTime' in event[attr]:
40070
40061
  try:
40071
- dateTime, _ = iso8601.parse_date(event[attr]['dateTime'])
40072
- event[attr]['dayOfWeek'] = calendarlib.day_abbr[dateTime.weekday()]
40073
- except (iso8601.ParseError, OverflowError):
40062
+ dateTime = arrow.get(event[attr]['dateTime'])
40063
+ event[attr]['dayOfWeek'] = DAYS_OF_WEEK[dateTime.weekday()]
40064
+ except (arrow.parser.ParserError, OverflowError):
40074
40065
  pass
40075
40066
 
40076
40067
  def _createCalendarEvents(user, origCal, function, calIds, count, body, parameters):
@@ -46864,7 +46855,7 @@ def doCreateInboundSSOCredential():
46864
46855
  count, Ent.Choose(Ent.INBOUND_SSO_CREDENTIALS, count)))
46865
46856
  if generateKey:
46866
46857
  privKey, pemData = _generatePrivateKeyAndPublicCert('', '', 'GAM', keySize, b64enc_pub=False)
46867
- timestamp = datetime.datetime.now(GC.Values[GC.TIMEZONE]).strftime('%Y%m%d-%I%M%S')
46858
+ timestamp = arrow.now(GC.Values[GC.TIMEZONE]).strftime('%Y%m%d-%I%M%S')
46868
46859
  priv_file = f'privatekey-{timestamp}.pem'
46869
46860
  writeFile(priv_file, privKey)
46870
46861
  writeStdout(Msg.WROTE_PRIVATE_KEY_DATA.format(priv_file))
@@ -47936,8 +47927,8 @@ class CourseAttributes():
47936
47927
  def checkDueDate(self, body):
47937
47928
  if 'dueDate' in body and 'dueTime' in body:
47938
47929
  try:
47939
- return self.currDateTime < datetime.datetime(body['dueDate']['year'], body['dueDate']['month'], body['dueDate']['day'],
47940
- body['dueTime'].get('hours', 0), body['dueTime'].get('minutes', 0), tzinfo=iso8601.UTC)
47930
+ return self.currDateTime < arrow.Arrow(body['dueDate']['year'], body['dueDate']['month'], body['dueDate']['day'],
47931
+ body['dueTime'].get('hours', 0), body['dueTime'].get('minutes', 0), tzinfo='UTC')
47941
47932
  except ValueError:
47942
47933
  pass
47943
47934
  return False
@@ -48119,7 +48110,7 @@ class CourseAttributes():
48119
48110
  entityPerformActionModifierItemValueList([Ent.COURSE, newCourse['id']], Act.MODIFIER_FROM, [Ent.COURSE, self.courseId], i, count)
48120
48111
  Ind.Increment()
48121
48112
  if not self.removeDueDate:
48122
- self.currDateTime = datetime.datetime.now(iso8601.UTC)
48113
+ self.currDateTime = arrow.utcnow()
48123
48114
  self.CopyAttributes(newCourse, i, count)
48124
48115
  if self.csvPF:
48125
48116
  self.csvPF.writeCSVfile('Course Drive File IDs')
@@ -48699,7 +48690,7 @@ def _courseItemPassesFilter(item, courseItemFilter):
48699
48690
  return False
48700
48691
  startTime = courseItemFilter['startTime']
48701
48692
  endTime = courseItemFilter['endTime']
48702
- timeValue, _ = iso8601.parse_date(timeStr)
48693
+ timeValue = arrow.get(timeStr)
48703
48694
  return ((startTime is None) or (timeValue >= startTime)) and ((endTime is None) or (timeValue <= endTime))
48704
48695
 
48705
48696
  def _gettingCoursesQuery(courseSelectionParameters):
@@ -53330,22 +53321,21 @@ def getStatusEventDateTime(dateType, dateList):
53330
53321
  firstDate = getYYYYMMDD(minLen=1, returnDateTime=True).replace(tzinfo=GC.Values[GC.TIMEZONE])
53331
53322
  if dateType == 'range':
53332
53323
  lastDate = getYYYYMMDD(minLen=1, returnDateTime=True).replace(tzinfo=GC.Values[GC.TIMEZONE])
53333
- deltaDay = datetime.timedelta(days=1)
53334
- deltaWeek = datetime.timedelta(weeks=1)
53335
53324
  if dateType in {'date', 'allday'}:
53336
- dateList.append({'type': 'date', 'first': firstDate, 'last': firstDate+deltaDay,
53337
- 'ulast': firstDate+deltaDay, 'udelta': deltaDay})
53325
+ dateList.append({'type': 'date', 'first': firstDate, 'last': firstDate.shift(days=1),
53326
+ 'ulast': firstDate.shift(days=1), 'udelta': {'days': 1}})
53338
53327
  elif dateType == 'range':
53339
- dateList.append({'type': dateType, 'first': firstDate, 'last': lastDate+deltaDay,
53340
- 'ulast': lastDate, 'udelta': deltaDay})
53328
+ dateList.append({'type': dateType, 'first': firstDate, 'last': lastDate.shift(days=1),
53329
+ 'ulast': lastDate, 'udelta': {'days': 1}})
53341
53330
  elif dateType == 'daily':
53342
53331
  argRepeat = getInteger(minVal=1, maxVal=366)
53343
- dateList.append({'type': dateType, 'first': firstDate, 'last': firstDate+datetime.timedelta(days=argRepeat),
53344
- 'ulast': firstDate+datetime.timedelta(days=argRepeat), 'udelta': deltaDay})
53332
+ dateList.append({'type': dateType, 'first': firstDate, 'last': firstDate.shift(days=argRepeat),
53333
+ 'ulast': firstDate.shift(days=argRepeat), 'udelta': {'days': 1}})
53345
53334
  else: #weekly
53346
53335
  argRepeat = getInteger(minVal=1, maxVal=52)
53347
- dateList.append({'type': dateType, 'first': firstDate, 'last': firstDate+deltaDay, 'pdelta': deltaWeek, 'repeats': argRepeat,
53348
- 'ulast': firstDate+datetime.timedelta(weeks=argRepeat), 'udelta': deltaWeek})
53336
+ dateList.append({'type': dateType, 'first': firstDate, 'last': firstDate.shift(days=1),
53337
+ 'pdelta': {'weeks': 1}, 'repeats': argRepeat,
53338
+ 'ulast': firstDate.shift(weeks=argRepeat), 'udelta': {'weeks': 1}})
53349
53339
 
53350
53340
  def _showCalendarStatusEvent(primaryEmail, calId, eventEntityType, event, k, kcount, FJQC):
53351
53341
  if FJQC.formatJSON:
@@ -53533,7 +53523,7 @@ def createStatusEvent(users, eventType):
53533
53523
  if wlDate['type'] != 'timerange':
53534
53524
  body['start']['date'] = first.strftime(YYYYMMDD_FORMAT)
53535
53525
  kvList[5] = body['start']['date']
53536
- body['end']['date'] = (first+datetime.timedelta(days=1)).strftime(YYYYMMDD_FORMAT)
53526
+ body['end']['date'] = (first.shift(days=1)).strftime(YYYYMMDD_FORMAT)
53537
53527
  else:
53538
53528
  body['start']['dateTime'] = ISOformatTimeStamp(first)
53539
53529
  kvList[5] = body['start']['dateTime']
@@ -53552,7 +53542,7 @@ def createStatusEvent(users, eventType):
53552
53542
  entityActionPerformed(kvList, j, jcount)
53553
53543
  if wlDate['type'] == 'timerange':
53554
53544
  break
53555
- first += wlDate['udelta']
53545
+ first = first.shift(**wlDate['udelta'])
53556
53546
  except (GAPI.forbidden, GAPI.invalid) as e:
53557
53547
  entityActionFailedWarning([Ent.CALENDAR, user], str(e), i, count)
53558
53548
  break
@@ -53753,8 +53743,8 @@ def printShowStatusEvent(users, eventType):
53753
53743
  _getEventDaysOfWeek(event)
53754
53744
  _printCalendarEvent(user, calId, event, csvPF, FJQC)
53755
53745
  if 'pdelta' in wlDate:
53756
- first += wlDate['pdelta']
53757
- last += wlDate['pdelta']
53746
+ first = first.shift(**wlDate['pdelta'])
53747
+ last = last.shift(**wlDate['pdelta'])
53758
53748
  if csvPF:
53759
53749
  csvPF.writeCSVfile(f'Calendar {Ent.Plural(entityType)}')
53760
53750
 
@@ -56258,7 +56248,7 @@ def _selectRevisionIds(drive, fileId, origUser, user, i, count, j, jcount, revis
56258
56248
  count = 0
56259
56249
  if revisionsEntity['time'][0] == 'before':
56260
56250
  for revision in results:
56261
- modifiedDateTime, _ = iso8601.parse_date(revision['modifiedTime'])
56251
+ modifiedDateTime = arrow.get(revision['modifiedTime'])
56262
56252
  if modifiedDateTime >= dateTime:
56263
56253
  break
56264
56254
  revisionIds.append(revision['id'])
@@ -56268,7 +56258,7 @@ def _selectRevisionIds(drive, fileId, origUser, user, i, count, j, jcount, revis
56268
56258
  return revisionIds
56269
56259
  # time: after
56270
56260
  for revision in results:
56271
- modifiedDateTime, _ = iso8601.parse_date(revision['modifiedTime'])
56261
+ modifiedDateTime = arrow.get(revision['modifiedTime'])
56272
56262
  if modifiedDateTime >= dateTime:
56273
56263
  revisionIds.append(revision['id'])
56274
56264
  count += 1
@@ -56280,7 +56270,7 @@ def _selectRevisionIds(drive, fileId, origUser, user, i, count, j, jcount, revis
56280
56270
  endDateTime = revisionsEntity['range'][2]
56281
56271
  count = 0
56282
56272
  for revision in results:
56283
- modifiedDateTime, _ = iso8601.parse_date(revision['modifiedTime'])
56273
+ modifiedDateTime = arrow.get(revision['modifiedTime'])
56284
56274
  if modifiedDateTime >= startDateTime:
56285
56275
  if modifiedDateTime >= endDateTime:
56286
56276
  break
@@ -56490,7 +56480,7 @@ def _selectRevisionResults(results, fileId, origUser, revisionsEntity, previewDe
56490
56480
  count = 0
56491
56481
  if revisionsEntity['time'][0] == 'before':
56492
56482
  for revision in results:
56493
- modifiedDateTime, _ = iso8601.parse_date(revision['modifiedTime'])
56483
+ modifiedDateTime = arrow.get(revision['modifiedTime'])
56494
56484
  if modifiedDateTime >= dateTime:
56495
56485
  break
56496
56486
  count += 1
@@ -56501,7 +56491,7 @@ def _selectRevisionResults(results, fileId, origUser, revisionsEntity, previewDe
56501
56491
  return results[:count]
56502
56492
  # time: after
56503
56493
  for revision in results:
56504
- modifiedDateTime, _ = iso8601.parse_date(revision['modifiedTime'])
56494
+ modifiedDateTime = arrow.get(revision['modifiedTime'])
56505
56495
  if modifiedDateTime >= dateTime:
56506
56496
  break
56507
56497
  count += 1
@@ -56518,7 +56508,7 @@ def _selectRevisionResults(results, fileId, origUser, revisionsEntity, previewDe
56518
56508
  count = 0
56519
56509
  selectedResults = []
56520
56510
  for revision in results:
56521
- modifiedDateTime, _ = iso8601.parse_date(revision['modifiedTime'])
56511
+ modifiedDateTime = arrow.get(revision['modifiedTime'])
56522
56512
  if modifiedDateTime >= startDateTime:
56523
56513
  if modifiedDateTime >= endDateTime:
56524
56514
  break
@@ -57056,7 +57046,7 @@ class PermissionMatch():
57056
57046
  break
57057
57047
  elif field in {'expirationstart', 'expirationend'}:
57058
57048
  if 'expirationTime' in permission:
57059
- expirationDateTime, _ = iso8601.parse_date(permission['expirationTime'])
57049
+ expirationDateTime = arrow.get(permission['expirationTime'])
57060
57050
  if field == 'expirationstart':
57061
57051
  if expirationDateTime < value:
57062
57052
  break
@@ -59539,7 +59529,7 @@ def processFilenameReplacements(name, replacements):
59539
59529
  return name
59540
59530
 
59541
59531
  def addTimestampToFilename(parameters, body):
59542
- tdtime = datetime.datetime.now(GC.Values[GC.TIMEZONE])
59532
+ tdtime = arrow.now(GC.Values[GC.TIMEZONE])
59543
59533
  body['name'] += ' - '
59544
59534
  if not parameters[DFA_TIMEFORMAT]:
59545
59535
  body['name'] += ISOformatTimeStamp(tdtime)
@@ -71667,8 +71657,8 @@ def _mapMessageQueryDates(parameters):
71667
71657
  if not mg:
71668
71658
  break
71669
71659
  try:
71670
- dt = datetime.datetime(int(mg.groups()[1]), int(mg.groups()[2]), int(mg.groups()[3]), tzinfo=GC.Values[GC.TIMEZONE])
71671
- query = query[:mg.start(2)]+str(int(datetime.datetime.timestamp(dt)))+query[mg.end(4):]
71660
+ dt = arrow.Arrow(int(mg.groups()[1]), int(mg.groups()[2]), int(mg.groups()[3]), tzinfo=GC.Values[GC.TIMEZONE])
71661
+ query = query[:mg.start(2)]+str(dt.int_timestamp)+query[mg.end(4):]
71672
71662
  except ValueError:
71673
71663
  pass
71674
71664
  pos = mg.end()
@@ -72849,9 +72839,9 @@ def printShowMessagesThreads(users, entityType):
72849
72839
  if pLoc > 0:
72850
72840
  dateTimeValue = dateTimeValue[:pLoc]
72851
72841
  try:
72852
- dateTimeValue = datetime.datetime.strptime(dateTimeValue, RFC2822_TIME_FORMAT)
72842
+ dateTimeValue = arrow.Arrow.strptime(dateTimeValue, RFC2822_TIME_FORMAT)
72853
72843
  if dateHeaderConvertTimezone:
72854
- dateTimeValue = dateTimeValue.astimezone(GC.Values[GC.TIMEZONE])
72844
+ dateTimeValue = dateTimeValue.to(GC.Values[GC.TIMEZONE])
72855
72845
  return dateTimeValue.strftime(dateHeaderFormat)
72856
72846
  except ValueError:
72857
72847
  return headerValue