Source
import re
from datetime import UTC, timezone, tzinfo
import dateparser
import demistomock as demisto # noqa: F401
import pytz
from CommonServerPython import * # noqa: F401
def timezone_abbreviations(utc_offset: Optional[timedelta]) -> set[str]:
tznames = set()
if utc_offset is not None:
now = datetime.now(pytz.utc)
for tz in map(pytz.timezone, pytz.all_timezones_set):
if (d := now.astimezone(tz)).utcoffset() == utc_offset and (tzname := d.tzname()) and tzname[0:1] not in ("+", "-"):
tznames.add(tzname)
return tznames
def detect_time_zone(value: Any) -> tzinfo:
if isinstance(value, int):
return timezone(timedelta(minutes=value))
if isinstance(value, str):
value = value.strip()
if value == "Z":
return timezone(timedelta(hours=0))
elif m := re.fullmatch("([+-])([0-9]{1,2})(:?([0-9]{2}))?", value):
# +H, +HMM, +HHMM, +H:MM, +HH:MM
offset = ((int(m[2]) * 60) + int(m[4] or 0)) * (-1 if m[1] == "-" else 1)
return timezone(timedelta(minutes=offset))
elif m := re.match(r"(^|\s)(UTC|GMT)([+-])([0-9]{1,2})(:?([0-9]{2}))?($|\s)", value):
# Includes: UTC+H, UTC+HMM, UTC+HHMM, UTC+H:MM, UTC+HH:MM
offset = ((int(m[4]) * 60) + int(m[6] or 0)) * (-1 if m[3] == "-" else 1)
return timezone(timedelta(minutes=offset))
else:
# Try to parse as zone info
try:
return pytz.timezone(value)
except Exception:
pass
# Try to parse as time string
try:
d = dateparser.parse(value)
if d is not None and d.tzinfo is not None:
return d.tzinfo
except Exception:
pass
raise DemistoException(f"Unable to extract time zone - {value}")
def parse_date_time_value(value: Any) -> datetime:
"""Parse a date time value
:param value: The date or time to parse
:return: aware datetime object
"""
if value in [None, ""]:
return datetime.now(UTC)
if isinstance(value, int):
# Parse as time stamp
try:
# Considered the value as seconds > milliseconds > microseconds when it's too large (> uint max).
# (Currently later than 2106-02-07 06:28:15)
while value > 4294967295:
value /= 1000
return datetime.fromtimestamp(value).astimezone(UTC)
except Exception as err:
raise DemistoException(f"Error with input date / time - {err}")
if isinstance(value, str):
value = value.strip()
try:
# Parse as time stamp
return parse_date_time_value(int(value))
except (TypeError, ValueError):
pass
try:
date_time = dateparser.parse(value)
assert date_time is not None, f"could not parse {value}"
if date_time.tzinfo is not None:
return date_time
date_time = dateparser.parse(value, settings={"TIMEZONE": "UTC", "RETURN_AS_TIMEZONE_AWARE": True})
assert date_time is not None, f"could not parse {value}"
return date_time
except Exception as err:
raise DemistoException(f"Error with input date / time - {err}")
def main():
try:
args = demisto.args()
date_time = parse_date_time_value(args.get("value"))
if time_zone := args.get("time_zone"):
date_time = date_time.astimezone(detect_time_zone(time_zone))
time_components = {
"year": date_time.year,
"year_4_digit": date_time.strftime("%Y"),
"month": date_time.month,
"month_3_letter": date_time.strftime("%b"),
"month_full_name": date_time.strftime("%B"),
"month_2_digit": date_time.strftime("%m"),
"day": date_time.day,
"day_2_digit": date_time.strftime("%d"),
"day_of_week": int(date_time.strftime("%w")),
"day_of_week_3_letter": date_time.strftime("%a"),
"day_of_week_full_name": date_time.strftime("%A"),
"day_of_year": int(date_time.strftime("%j")),
"day_of_year_3_digit": date_time.strftime("%j"),
"hour": date_time.hour,
"hour_12_clock": (date_time.hour % 12) or 12,
"hour_2_digit_24_clock": date_time.strftime("%H"),
"hour_2_digit_12_clock": date_time.strftime("%I"),
"hour_of_day": date_time.hour + (date_time.minute / 60) + (date_time.second / 60 / 60),
"minute": date_time.minute,
"minute_2_digit": date_time.strftime("%M"),
"minute_of_day": (date_time.hour * 24) + date_time.minute + (date_time.second / 60),
"second": date_time.second,
"second_2_digit": date_time.strftime("%S"),
"second_of_day": (date_time.hour * 24 * 60) + (date_time.minute * 60) + date_time.second,
"millisecond": int(date_time.microsecond / 1000),
"period_12_clock": date_time.strftime("%p"),
"time_zone_hhmm": date_time.strftime("%z"),
"time_zone_offset": (date_time.utcoffset() or timedelta(hours=0)).total_seconds() / 60,
"time_zone_abbreviations": sorted(timezone_abbreviations(date_time.utcoffset())),
"unix_epoch_time": int(date_time.timestamp()),
"iso_8601": date_time.isoformat(),
"y-m-d": f"{date_time.year}-{date_time.month}-{date_time.day}",
"yyyy-mm-dd": f"{date_time.strftime('%Y-%m-%d')}",
"h:m:s": f"{date_time.hour}:{date_time.minute}:{date_time.second}",
"H:m:s": f"{(date_time.hour % 12) or 12}:{date_time.minute}:{date_time.second}",
"hh:mm:ss": f"{date_time.strftime('%I:%M:%S')}",
"HH:mm:ss": f"{date_time.strftime('%H:%M:%S')}",
}
if key := args.get("key"):
if (component := time_components.get(key)) is None:
raise DemistoException(f"No key is found in the time components - {key}")
return_results(component)
else:
return_results(time_components)
except Exception as err:
# Don't return an error by return_error() as this is transformer.
raise DemistoException(str(err))
if __name__ in ("__main__", "builtin", "builtins"):
main()
README
Takes a date or time input and get time components in a specific time zone.
Returns a dictionary with the following components.
- year
- year_4_digit
- month
- month_3_letter
- month_full_name
- month_2_digit
- day
- day_2_digit
- day_of_week (Sun:0, Sat:6)
- day_of_week_3_letter
- day_of_week_full_name
- day_of_year
- day_of_year_3_digit
- hour
- hour_12_clock
- hour_2_digit_24_clock
- hour_2_digit_12_clock
- hour_of_day
- minute
- minute_2_digit
- minute_of_day
- second
- second_2_digit
- second_of_day
- millisecond
- period_12_clock
- time_zone_hhmm
- time_zone_offset
- time_zone_abbreviations
- unix_epoch_time
- iso_8601
- y-m-d
- yyyy-mm-dd
- h:m:s
- H:m:s
- hh:mm:ss
- HH:mm:ss
Script Data
| Name |
Description |
| Script Type |
python3 |
| Tags |
transformer, date |
| Cortex XSOAR Version |
6.5.0 |
Inputs
| Argument Name |
Description |
| value |
Input date or time in a format that is supported by the dateparser.parse() function as outlined here- https://dateparser.readthedocs.io/en/latest/#popular-formats. For example: ‘2020-01-01’ or ‘1999/02/03 12:01:59’. (Default is the current time). Assume given time is in UTC if time zone is not detected. |
| time_zone |
The time zone (e.g. -0400, +09:00) or time string to extract a time zone |
| key |
The name of a key to choose which time component to return |
Outputs
There are no outputs for this script.
Examples
Get all the time components from the time taken
Parameters
| Argument Name |
Value |
| value |
2022-01-23 01:23:45 +00:00 |
| time_zone |
|
| key |
|
Output
{
"year": 2022,
"year_4_digit": "2022",
"month": 1,
"month_3_letter": "Jan",
"month_full_name": "January",
"month_2_digit": "01",
"day": 23,
"day_2_digit": "23",
"day_of_week": 0,
"day_of_week_3_letter": "Sun",
"day_of_week_full_name": "Sunday",
"day_of_year": 23,
"day_of_year_3_digit": "023",
"hour": 1,
"hour_12_clock": 1,
"hour_2_digit_24_clock": "01",
"hour_2_digit_12_clock": "01",
"hour_of_day": 1.3958333333333333,
"minute": 23,
"minute_2_digit": "23",
"minute_of_day": 47.75,
"second": 45,
"second_2_digit": "45",
"second_of_day": 2865,
"millisecond": 0,
"period_12_clock": "AM",
"time_zone_hhmm": "+0000",
"time_zone_offset": 0.0,
"time_zone_abbreviations": ["GMT", "UTC", "WET"],
"unix_epoch_time": 1642901025,
"iso_8601": "2022-01-23T01:23:45+00:00",
"y-m-d": "2022-1-23",
"yyyy-mm-dd": "2022-01-23",
"h:m:s": "1:23:45",
"H:m:s": "1:23:45",
"hh:mm:ss": "01:23:45",
"HH:mm:ss": "01:23:45"
}
Get all the time components in a specific time zone
Parameters
| Argument Name |
Value |
| value |
2022-01-23 01:23:45 +00:00 |
| time_zone |
+09:00 |
| key |
|
Output
{
"year": 2022,
"year_4_digit": "2022",
"month": 1,
"month_3_letter": "Jan",
"month_full_name": "January",
"month_2_digit": "01",
"day": 23,
"day_2_digit": "23",
"day_of_week": 0,
"day_of_week_3_letter": "Sun",
"day_of_week_full_name": "Sunday",
"day_of_year": 23,
"day_of_year_3_digit": "023",
"hour": 10,
"hour_12_clock": 10,
"hour_2_digit_24_clock": "10",
"hour_2_digit_12_clock": "10",
"hour_of_day": 10.395833333333332,
"minute": 23,
"minute_2_digit": "23",
"minute_of_day": 263.75,
"second": 45,
"second_2_digit": "45",
"second_of_day": 15825,
"millisecond": 0,
"period_12_clock": "AM",
"time_zone_hhmm": "+0900",
"time_zone_offset": 540.0,
"time_zone_abbreviations": ["JST", "KST", "WIT"],
"unix_epoch_time": 1642901025,
"iso_8601": "2022-01-23T10:23:45+09:00",
"y-m-d": "2022-1-23",
"yyyy-mm-dd": "2022-01-23",
"h:m:s": "10:23:45",
"H:m:s": "10:23:45",
"hh:mm:ss": "10:23:45",
"HH:mm:ss": "10:23:45"
}
Get all the time components from the unix timestamp
Parameters
| Argument Name |
Value |
| value |
1642868625 |
| time_zone |
|
| key |
|
Output
{
"year": 2022,
"year_4_digit": "2022",
"month": 1,
"month_3_letter": "Jan",
"month_full_name": "January",
"month_2_digit": "01",
"day": 22,
"day_2_digit": "22",
"day_of_week": 6,
"day_of_week_3_letter": "Sat",
"day_of_week_full_name": "Saturday",
"day_of_year": 22,
"day_of_year_3_digit": "022",
"hour": 16,
"hour_12_clock": 4,
"hour_2_digit_24_clock": "16",
"hour_2_digit_12_clock": "04",
"hour_of_day": 16.395833333333332,
"minute": 23,
"minute_2_digit": "23",
"minute_of_day": 407.75,
"second": 45,
"second_2_digit": "45",
"second_of_day": 24465,
"millisecond": 0,
"period_12_clock": "PM",
"time_zone_hhmm": "+0000",
"time_zone_offset": 0.0,
"time_zone_abbreviations": ["GMT", "UTC", "WET"],
"unix_epoch_time": 1642868625,
"iso_8601": "2022-01-22T16:23:45+00:00",
"y-m-d": "2022-1-22",
"yyyy-mm-dd": "2022-01-22",
"h:m:s": "16:23:45",
"H:m:s": "4:23:45",
"hh:mm:ss": "04:23:45",
"HH:mm:ss": "16:23:45"
}
Get a specific time component (day_of_week_full_name)
Parameters
| Argument Name |
Value |
| value |
2022-01-23 01:23:45 +00:00 |
| time_zone |
|
| key |
day_of_week_full_name |
Output
Sunday
Get a time component in a specific time zone given by zone info
Parameters
| Argument Name |
Value |
| value |
2022-01-23 01:23:45 +00:00 |
| time_zone |
Asia/Tokyo |
| key |
iso_8601 |
Output
2022-01-23T10:23:45+09:00
Get a time component in a time zone which is extracted from the time string given to time_zone
Parameters
| Argument Name |
Value |
| value |
2022-01-23 01:23:45 +00:00 |
| time_zone |
2022-01-01 00:00:00 +09:00 |
| key |
iso_8601 |
Output
2022-01-23T10:23:45+09:00
Get a current time in a specific time zone
Parameters
| Argument Name |
Value |
| value |
now |
| time_zone |
+09:00 |
| key |
iso_8601 |
Output
2022-09-30T12:34:56+09:00
Tips
Build a custom time format string
You can create a custom time format in combination with the DT transformer on the chain of transformers. For example, now you want to create a RFC 1123 date string such as Thu, 10 Nov 2022 08:01:44 +0200, and have the following results from the TimeComponents.
Table 1
{
"year": 2022,
"year_4_digit": "2022",
"month": 11,
"month_3_letter": "Nov",
"month_full_name": "November",
"month_2_digit": "11",
"day": 10,
"day_2_digit": "10",
"day_of_week": 4,
"day_of_week_3_letter": "Thu",
"day_of_week_full_name": "Thursday",
"day_of_year": 314,
"day_of_year_3_digit": "314",
"hour": 8,
"hour_12_clock": 8,
"hour_2_digit_24_clock": "08",
"hour_2_digit_12_clock": "08",
"hour_of_day": 8.02888888888889,
"minute": 1,
"minute_2_digit": "01",
"minute_of_day": 193.73333333333332,
"second": 44,
"second_2_digit": "44",
"second_of_day": 11624,
"millisecond": 0,
"period_12_clock": "AM",
"time_zone_hhmm": "+0200",
"time_zone_offset": 120.0,
"unix_epoch_time": 1668060104,
"iso_8601": "2022-11-10T08:01:44+02:00",
"y-m-d": "2022-11-10",
"yyyy-mm-dd": "2022-11-10",
"h:m:s": "8:1:44",
"H:m:s": "8:1:44",
"hh:mm:ss": "08:01:44",
"HH:mm:ss": "08:01:44"
}
You can set the following value to the dt parameter of the DT transformer to build the RFC 1123 date string you want.
Parameters to DT
| Argument Name |
Value |
| value |
<Table 1> |
| dt |
.=val.day_of_week_3_letter + “, “ + val.day + “ “ + val.month_3_letter + “ “ + val.year + “ “ + val[“HH:mm:ss”] + “ “ + val.time_zone_hhmm |
Output
Thu, 10 Nov 2022 08:01:44 +0200