forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			115 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			115 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # This Source Code Form is subject to the terms of the Mozilla Public
 | |
| # License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
| # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | |
| 
 | |
| # Python port of the ms.js node module this is not a direct port some things are
 | |
| # more complicated or less precise and we lean on time delta here.
 | |
| 
 | |
| 
 | |
| import datetime
 | |
| import re
 | |
| 
 | |
| PATTERN = re.compile(r"((?:\d+)?\.?\d+) *([a-z]+)")
 | |
| 
 | |
| 
 | |
| def seconds(value):
 | |
|     return datetime.timedelta(seconds=int(value))
 | |
| 
 | |
| 
 | |
| def minutes(value):
 | |
|     return datetime.timedelta(minutes=int(value))
 | |
| 
 | |
| 
 | |
| def hours(value):
 | |
|     return datetime.timedelta(hours=int(value))
 | |
| 
 | |
| 
 | |
| def days(value):
 | |
|     return datetime.timedelta(days=int(value))
 | |
| 
 | |
| 
 | |
| def months(value):
 | |
|     # See warning in years(), below
 | |
|     return datetime.timedelta(days=int(value) * 30)
 | |
| 
 | |
| 
 | |
| def years(value):
 | |
|     # Warning here "years" are vague don't use this for really sensitive date
 | |
|     # computation the idea is to give you a absolute amount of time in the
 | |
|     # future which is not the same thing as "precisely on this date next year"
 | |
|     return datetime.timedelta(days=int(value) * 365)
 | |
| 
 | |
| 
 | |
| ALIASES = {}
 | |
| ALIASES["seconds"] = ALIASES["second"] = ALIASES["s"] = seconds
 | |
| ALIASES["minutes"] = ALIASES["minute"] = ALIASES["min"] = minutes
 | |
| ALIASES["hours"] = ALIASES["hour"] = ALIASES["h"] = hours
 | |
| ALIASES["days"] = ALIASES["day"] = ALIASES["d"] = days
 | |
| ALIASES["months"] = ALIASES["month"] = ALIASES["mo"] = months
 | |
| ALIASES["years"] = ALIASES["year"] = ALIASES["y"] = years
 | |
| 
 | |
| 
 | |
| class InvalidString(Exception):
 | |
|     pass
 | |
| 
 | |
| 
 | |
| class UnknownTimeMeasurement(Exception):
 | |
|     pass
 | |
| 
 | |
| 
 | |
| def value_of(input_str):
 | |
|     """
 | |
|     Convert a string to a json date in the future
 | |
|     :param str input_str: (ex: 1d, 2d, 6years, 2 seconds)
 | |
|     :returns: Unit given in seconds
 | |
|     """
 | |
| 
 | |
|     matches = PATTERN.search(input_str)
 | |
| 
 | |
|     if matches is None or len(matches.groups()) < 2:
 | |
|         raise InvalidString(f"'{input_str}' is invalid string")
 | |
| 
 | |
|     value, unit = matches.groups()
 | |
| 
 | |
|     if unit not in ALIASES:
 | |
|         raise UnknownTimeMeasurement(
 | |
|             "{} is not a valid time measure use one of {}".format(
 | |
|                 unit, sorted(ALIASES.keys())
 | |
|             )
 | |
|         )
 | |
| 
 | |
|     return ALIASES[unit](value)
 | |
| 
 | |
| 
 | |
| def json_time_from_now(input_str, now=None, datetime_format=False):
 | |
|     """
 | |
|     :param str input_str: Input string (see value of)
 | |
|     :param datetime now: Optionally set the definition of `now`
 | |
|     :param boolean datetime_format: Set `True` to get a `datetime` output
 | |
|     :returns: JSON string representation of time in future.
 | |
|     """
 | |
| 
 | |
|     if now is None:
 | |
|         now = datetime.datetime.utcnow()
 | |
| 
 | |
|     time = now + value_of(input_str)
 | |
| 
 | |
|     if datetime_format is True:
 | |
|         return time
 | |
|     else:
 | |
|         # Sorta a big hack but the json schema validator for date does not like the
 | |
|         # ISO dates until 'Z' (for timezone) is added...
 | |
|         # Microseconds are excluded (see bug 1381801)
 | |
|         return time.isoformat(timespec="milliseconds") + "Z"
 | |
| 
 | |
| 
 | |
| def current_json_time(datetime_format=False):
 | |
|     """
 | |
|     :param boolean datetime_format: Set `True` to get a `datetime` output
 | |
|     :returns: JSON string representation of the current time.
 | |
|     """
 | |
|     if datetime_format is True:
 | |
|         return datetime.datetime.utcnow()
 | |
|     else:
 | |
|         # Microseconds are excluded (see bug 1381801)
 | |
|         return datetime.datetime.utcnow().isoformat(timespec="milliseconds") + "Z"
 | 
