New upstream release.
Debian Janitor
2 years ago
5 | 5 | runs-on: ubuntu-latest |
6 | 6 | strategy: |
7 | 7 | matrix: |
8 | version: ['32', '33', '34'] | |
8 | version: ['34', '35'] | |
9 | 9 | container: |
10 | 10 | image: registry.fedoraproject.org/fedora:${{ matrix.version }} |
11 | 11 | steps: |
16 | 16 | - name: Install dependencies |
17 | 17 | run: | |
18 | 18 | dnf copr -y enable @gift/dev |
19 | dnf install -y python3 python3-mock python3-pbr python3-setuptools python3-six | |
19 | dnf install -y @development-tools python3 python3-devel python3-mock python3-pbr python3-setuptools python3-six | |
20 | 20 | - name: Run tests |
21 | 21 | env: |
22 | 22 | LANG: C.utf8 |
56 | 56 | run: | |
57 | 57 | add-apt-repository -y ppa:gift/dev |
58 | 58 | apt-get update -q |
59 | apt-get install -y python3 python3-distutils python3-mock python3-pbr python3-setuptools python3-six | |
59 | apt-get install -y build-essential python3 python3-dev python3-distutils python3-mock python3-pbr python3-setuptools python3-six | |
60 | 60 | - name: Run tests |
61 | 61 | env: |
62 | 62 | LANG: en_US.UTF-8 |
0 | 0 | # Run tox tests on Ubuntu Docker images using GIFT PPA |
1 | 1 | name: test_tox |
2 | on: [push, pull_request] | |
2 | on: | |
3 | pull_request: | |
4 | branches: | |
5 | - main | |
6 | push: | |
7 | branches: | |
8 | - main | |
3 | 9 | jobs: |
4 | 10 | build: |
5 | 11 | runs-on: ubuntu-latest |
6 | 12 | strategy: |
7 | 13 | matrix: |
8 | 14 | include: |
9 | - python-version: 3.6 | |
15 | - python-version: '3.6' | |
10 | 16 | toxenv: 'py36' |
11 | - python-version: 3.7 | |
17 | - python-version: '3.7' | |
12 | 18 | toxenv: 'py37' |
13 | - python-version: 3.8 | |
19 | - python-version: '3.8' | |
14 | 20 | toxenv: 'py38,coverage,codecov' |
15 | - python-version: 3.8 | |
21 | - python-version: '3.9' | |
22 | toxenv: 'py39' | |
23 | - python-version: '3.10' | |
24 | toxenv: 'py310' | |
25 | - python-version: '3.8' | |
16 | 26 | toxenv: 'pylint' |
17 | - python-version: 3.8 | |
27 | - python-version: '3.8' | |
18 | 28 | toxenv: 'docs' |
19 | 29 | container: |
20 | 30 | image: ubuntu:20.04 |
36 | 46 | add-apt-repository -y ppa:deadsnakes/ppa |
37 | 47 | add-apt-repository -y ppa:gift/dev |
38 | 48 | apt-get update -q |
39 | apt-get install -y build-essential git python${{ matrix.python-version }} python${{ matrix.python-version }}-dev tox python3-distutils python3-mock python3-pbr python3-setuptools python3-six | |
49 | apt-get install -y build-essential git libffi-dev python${{ matrix.python-version }} python${{ matrix.python-version }}-dev python${{ matrix.python-version }}-venv python3-distutils python3-mock python3-pbr python3-pip python3-setuptools python3-six | |
50 | - name: Install tox | |
51 | run: | | |
52 | python3 -m pip install tox | |
40 | 53 | - name: Run tests |
41 | 54 | env: |
42 | 55 | LANG: en_US.UTF-8 |
0 | # Pylint 2.6.x configuration file | |
0 | # Pylint 2.9.x configuration file | |
1 | 1 | # |
2 | 2 | # This file is generated by l2tdevtools update-dependencies.py, any dependency |
3 | 3 | # related changes should be made in dependencies.ini. |
6 | 6 | # A comma-separated list of package or module names from where C extensions may |
7 | 7 | # be loaded. Extensions are loading into the active Python interpreter and may |
8 | 8 | # run arbitrary code. |
9 | extension-pkg-allow-list= | |
10 | ||
11 | # A comma-separated list of package or module names from where C extensions may | |
12 | # be loaded. Extensions are loading into the active Python interpreter and may | |
13 | # run arbitrary code. (This is an alternative name to extension-pkg-allow-list | |
14 | # for backward compatibility.) | |
9 | 15 | extension-pkg-whitelist= |
16 | ||
17 | # Return non-zero exit code if any of these messages/categories are detected, | |
18 | # even if score is above --fail-under value. Syntax same as enable. Messages | |
19 | # specified are enabled, while categories only check already-enabled messages. | |
20 | fail-on= | |
10 | 21 | |
11 | 22 | # Specify a score threshold to be exceeded before program exits with error. |
12 | 23 | fail-under=10.0 |
13 | 24 | |
14 | # Add files or directories to the blacklist. They should be base names, not | |
15 | # paths. | |
25 | # Files or directories to be skipped. They should be base names, not paths. | |
16 | 26 | ignore=CVS |
17 | 27 | |
18 | # Add files or directories matching the regex patterns to the blacklist. The | |
19 | # regex matches against base names, not paths. | |
28 | # Add files or directories matching the regex patterns to the ignore-list. The | |
29 | # regex matches against paths. | |
30 | ignore-paths= | |
31 | ||
32 | # Files or directories matching the regex patterns are skipped. The regex | |
33 | # matches against base names, not paths. | |
20 | 34 | ignore-patterns= |
21 | 35 | |
22 | 36 | # Python code to execute, usually for sys.path manipulation such as |
101 | 115 | # either give multiple identifier separated by comma (,) or put this option |
102 | 116 | # multiple time (only on the command line, not in the configuration file where |
103 | 117 | # it should appear only once). See also the "--disable" option for examples. |
104 | enable= | |
118 | enable=c-extension-no-member | |
105 | 119 | |
106 | 120 | |
107 | 121 | [REPORTS] |
138 | 152 | # inconsistent-return-statements if a never returning function is called then |
139 | 153 | # it will be considered as an explicit return statement and no message will be |
140 | 154 | # printed. |
141 | never-returning-functions=sys.exit | |
155 | never-returning-functions=sys.exit,argparse.parse_error | |
142 | 156 | |
143 | 157 | |
144 | 158 | [VARIABLES] |
149 | 163 | |
150 | 164 | # Tells whether unused global variables should be treated as a violation. |
151 | 165 | allow-global-unused-variables=yes |
166 | ||
167 | # List of names allowed to shadow builtins | |
168 | allowed-redefined-builtins= | |
152 | 169 | |
153 | 170 | # List of strings which can identify a callback function by name. A callback |
154 | 171 | # name must start or end with one of those strings. |
271 | 288 | # Regular expression matching correct class attribute names. Overrides class- |
272 | 289 | # attribute-naming-style. |
273 | 290 | class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]*|(__.*__))$ |
291 | ||
292 | # Naming style matching correct class constant names. | |
293 | class-const-naming-style=UPPER_CASE | |
294 | ||
295 | # Regular expression matching correct class constant names. Overrides class- | |
296 | # const-naming-style. | |
297 | #class-const-rgx= | |
274 | 298 | |
275 | 299 | # Naming style matching correct class names. |
276 | 300 | class-naming-style=PascalCase |
409 | 433 | # (hunspell), en_ZM (hunspell), en_ZW (hunspell). |
410 | 434 | spelling-dict= |
411 | 435 | |
436 | # List of comma separated words that should be considered directives if they | |
437 | # appear and the beginning of a comment and should not be checked. | |
438 | spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: | |
439 | ||
412 | 440 | # List of comma separated words that should not be checked. |
413 | 441 | spelling-ignore-words= |
414 | 442 | |
431 | 459 | # Ignore imports when computing similarities. |
432 | 460 | ignore-imports=no |
433 | 461 | |
462 | # Ignore function signatures when computing similarities. | |
463 | ignore-signatures=no | |
464 | ||
434 | 465 | # Minimum lines number of a similarity. |
435 | 466 | min-similarity-lines=4 |
436 | 467 | |
480 | 511 | |
481 | 512 | |
482 | 513 | [CLASSES] |
514 | ||
515 | # Warn about protected attribute access inside special methods | |
516 | check-protected-access-in-special-methods=no | |
483 | 517 | |
484 | 518 | # List of method names used to declare (i.e. assign) instance attributes. |
485 | 519 | defining-attr-methods=__init__, |
519 | 553 | # Deprecated modules which should not be used, separated by a comma. |
520 | 554 | deprecated-modules=optparse,tkinter.tix |
521 | 555 | |
522 | # Create a graph of external dependencies in the given file (report RP0402 must | |
523 | # not be disabled). | |
556 | # Output a graph (.gv or any supported image format) of external dependencies | |
557 | # to the given file (report RP0402 must not be disabled). | |
524 | 558 | ext-import-graph= |
525 | 559 | |
526 | # Create a graph of every (i.e. internal and external) dependencies in the | |
527 | # given file (report RP0402 must not be disabled). | |
560 | # Output a graph (.gv or any supported image format) of all (i.e. internal and | |
561 | # external) dependencies to the given file (report RP0402 must not be | |
562 | # disabled). | |
528 | 563 | import-graph= |
529 | 564 | |
530 | # Create a graph of internal dependencies in the given file (report RP0402 must | |
531 | # not be disabled). | |
565 | # Output a graph (.gv or any supported image format) of internal dependencies | |
566 | # to the given file (report RP0402 must not be disabled). | |
532 | 567 | int-import-graph= |
533 | 568 | |
534 | 569 | # Force import order to recognize a module as part of the standard |
540 | 575 | |
541 | 576 | # Couples of modules and preferred modules, separated by a comma. |
542 | 577 | preferred-modules= |
543 | ||
544 | ||
545 | [PARAMETER_DOCUMENTATION] | |
546 | ||
547 | # Whether to accept totally missing parameter documentation in the docstring of | |
548 | # a function that has parameters. | |
549 | accept-no-param-doc=yes | |
550 | ||
551 | # Whether to accept totally missing raises documentation in the docstring of a | |
552 | # function that raises an exception. | |
553 | accept-no-raise-doc=yes | |
554 | ||
555 | # Whether to accept totally missing return documentation in the docstring of a | |
556 | # function that returns a statement. | |
557 | accept-no-return-doc=yes | |
558 | ||
559 | # Whether to accept totally missing yields documentation in the docstring of a | |
560 | # generator. | |
561 | accept-no-yields-doc=yes | |
562 | ||
563 | # If the docstring type cannot be guessed the specified docstring type will be | |
564 | # used. | |
565 | default-docstring-type=default | |
566 | 578 | |
567 | 579 | |
568 | 580 | [EXCEPTIONS] |
0 | 0 | include ACKNOWLEDGEMENTS AUTHORS LICENSE README |
1 | 1 | include dependencies.ini run_tests.py utils/__init__.py utils/dependencies.py |
2 | 2 | include utils/check_dependencies.py |
3 | include requirements.txt test_requirements.txt | |
3 | 4 | exclude .gitignore |
4 | 5 | exclude *.pyc |
5 | 6 | recursive-include config * |
0 | 0 | environment: |
1 | pypi_token: | |
1 | PYPI_TOKEN: | |
2 | 2 | secure: /FwQrmudDyj+Mu3DaxLEo23Y6/OEgdHJqyWyZTjkJKje8pxCOrUorN8ZlXRGXbd3UA60emClt0M+SI+xqyA/qkpqZTgd5CKohpVAGH2EfzRc/zwJSGJ4tmZmMVAG8ayk6N9zFxCeC+y0BgZPQnj/Eq/RfuS4YIuaKutIUa5gTMmhWpODFKGV/2Wx1w67xWxAoONfEC5j0Gu3R274SS7FfBb4qWyIiBIJMwHGjlgp1Onk8KlpCLauZv8/hGfQDmWEdZ+mjcsTYyQYr1xfr1/FjQ== |
3 | 3 | matrix: |
4 | - DESCRIPTION: "Windows with 32-bit Python 3.9" | |
4 | - DESCRIPTION: "Windows with 32-bit Python 3.10" | |
5 | 5 | MACHINE_TYPE: "x86" |
6 | 6 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 |
7 | PYTHON: "C:\\Python39" | |
8 | PYTHON_VERSION: "3.9" | |
7 | PYTHON: "C:\\Python310" | |
8 | PYTHON_VERSION: "3.10" | |
9 | 9 | L2TBINARIES_TRACK: "dev" |
10 | - DESCRIPTION: "Windows with 64-bit Python 3.9" | |
10 | - DESCRIPTION: "Windows with 64-bit Python 3.10" | |
11 | 11 | MACHINE_TYPE: "amd64" |
12 | 12 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 |
13 | PYTHON: "C:\\Python39-x64" | |
14 | PYTHON_VERSION: "3.9" | |
13 | PYTHON: "C:\\Python310-x64" | |
14 | PYTHON_VERSION: "3.10" | |
15 | 15 | L2TBINARIES_TRACK: "dev" |
16 | - DESCRIPTION: "Mac OS with Python 3.9" | |
16 | - DESCRIPTION: "Mac OS with Python 3.10" | |
17 | 17 | APPVEYOR_BUILD_WORKER_IMAGE: macos |
18 | 18 | HOMEBREW_NO_INSTALL_CLEANUP: 1 |
19 | 19 | |
20 | 20 | install: |
21 | - cmd: "%PYTHON%\\python.exe -m pip install -U pip setuptools wheel" | |
21 | - cmd: "%PYTHON%\\python.exe -m pip install -U pip setuptools twine wheel" | |
22 | 22 | - cmd: "%PYTHON%\\python.exe -m pip install pywin32 WMI" |
23 | 23 | - cmd: "%PYTHON%\\python.exe %PYTHON%\\Scripts\\pywin32_postinstall.py -install" |
24 | 24 | - ps: If ($isWindows) { .\config\appveyor\install.ps1 } |
25 | 25 | - sh: config/appveyor/install.sh |
26 | 26 | |
27 | 27 | build_script: |
28 | - cmd: "%PYTHON%\\python.exe setup.py bdist_msi bdist_wheel" | |
28 | # Note that bdist_msi will change the version number to work-around limitations | |
29 | # of the MSI version version numbering. Hence a MSI build is done separately | |
30 | # from building the wheel to not influence its version number. | |
31 | - cmd: "%PYTHON%\\python.exe setup.py bdist_msi" | |
32 | - cmd: "%PYTHON%\\python.exe setup.py bdist_wheel" | |
29 | 33 | |
30 | 34 | test_script: |
31 | 35 | - cmd: "%PYTHON%\\python.exe run_tests.py" |
38 | 42 | - path: dist\*.whl |
39 | 43 | |
40 | 44 | deploy_script: |
41 | - ps: If ($env:APPVEYOR_REPO_TAG -eq "true" -And $isWindows) { | |
45 | - ps: If ($env:APPVEYOR_REPO_TAG -eq "true" -And $isWindows -And $env:MACHINE_TYPE -eq "x86") { | |
42 | 46 | Invoke-Expression "${env:PYTHON}\\python.exe -m twine upload dist/*.whl --username __token__ --password ${env:PYPI_TOKEN} --skip-existing" } |
43 |
5 | 5 | export LDFLAGS="-L/usr/local/lib -L/usr/local/opt/openssl@1.1/lib ${LDFLAGS}"; |
6 | 6 | export TOX_TESTENV_PASSENV="CFLAGS LDFLAGS"; |
7 | 7 | |
8 | # Set the following environment variables to ensure tox can find Python 3.9. | |
9 | export PATH="/usr/local/opt/python@3.9/bin:${PATH}"; | |
8 | # Set the following environment variables to ensure tox can find Python 3.10. | |
9 | export PATH="/usr/local/opt/python@3.10/bin:${PATH}"; | |
10 | 10 | |
11 | tox -e py39 | |
11 | tox -e py310 |
0 | dfdatetime (20210509-1) unstable; urgency=low | |
0 | dfdatetime (20220131-1) unstable; urgency=low | |
1 | 1 | |
2 | 2 | * Auto-generated |
3 | 3 | |
4 | -- Log2Timeline maintainers <log2timeline-maintainers@googlegroups.com> Sun, 09 May 2021 16:27:46 +0200 | |
4 | -- Log2Timeline maintainers <log2timeline-maintainers@googlegroups.com> Mon, 31 Jan 2022 12:59:15 +0100 |
8 | 8 | |
9 | 9 | Package: python3-dfdatetime |
10 | 10 | Architecture: all |
11 | Depends: ${python3:Depends}, ${misc:Depends} | |
11 | Depends: ${misc:Depends} | |
12 | 12 | Description: Python 3 module of dfDateTime |
13 | 13 | dfDateTime, or Digital Forensics date and time, provides date and time objects |
14 | 14 | to preserve accuracy and precision. |
0 | dfdatetime (20220131-1) UNRELEASED; urgency=low | |
1 | ||
2 | * New upstream release. | |
3 | ||
4 | -- Debian Janitor <janitor@jelmer.uk> Thu, 10 Mar 2022 08:11:14 -0000 | |
5 | ||
0 | 6 | dfdatetime (20210509-1) unstable; urgency=medium |
1 | 7 | |
2 | 8 | * Team upload. |
11 | 11 | from dfdatetime import fat_date_time |
12 | 12 | from dfdatetime import filetime |
13 | 13 | from dfdatetime import hfs_time |
14 | from dfdatetime import golang_time | |
14 | 15 | from dfdatetime import java_time |
15 | 16 | from dfdatetime import ole_automation_date |
16 | 17 | from dfdatetime import posix_time |
19 | 20 | from dfdatetime import systemtime |
20 | 21 | from dfdatetime import time_elements |
21 | 22 | from dfdatetime import uuid_time |
23 | from dfdatetime import webkit_time | |
22 | 24 | |
23 | __version__ = '20210509' | |
25 | ||
26 | __version__ = '20220131' |
17 | 17 | MICROSECONDS_PER_DECISECOND = 100000 |
18 | 18 | MICROSECONDS_PER_MILLISECOND = 1000 |
19 | 19 | |
20 | NANOSECONDS_PER_MICROSECOND = 1000 | |
20 | 21 | NANOSECONDS_PER_SECOND = 1000000000 |
21 | 22 | |
22 | 23 | PRECISION_1_DAY = '1d' |
26 | 26 | 9999-12-31 23:59:59.999 |
27 | 27 | |
28 | 28 | Also see: |
29 | http://docwiki.embarcadero.com/Libraries/XE3/en/System.TDateTime | |
29 | https://docwiki.embarcadero.com/Libraries/XE3/en/System.TDateTime | |
30 | 30 | |
31 | 31 | Attributes: |
32 | 32 | is_local_time (bool): True if the date and time value is in local time. |
63 | 63 | if (self._timestamp is not None and self._timestamp >= 0 and |
64 | 64 | self._timestamp <= self._UINT64_MAX): |
65 | 65 | self._normalized_timestamp = ( |
66 | decimal.Decimal(self._timestamp) / self._100NS_PER_SECOND) | |
66 | decimal.Decimal(self._timestamp) / self._100_NANOSECONDS_PER_SECOND) | |
67 | 67 | self._normalized_timestamp -= self._FILETIME_TO_POSIX_BASE |
68 | 68 | |
69 | 69 | if self._time_zone_offset: |
104 | 104 | timestamp += self._FILETIME_TO_POSIX_BASE |
105 | 105 | timestamp *= definitions.MICROSECONDS_PER_SECOND |
106 | 106 | timestamp += date_time_values.get('microseconds', 0) |
107 | timestamp *= self._100NS_PER_MICROSECOND | |
107 | timestamp *= self._100_NANOSECONDS_PER_MICROSECOND | |
108 | 108 | |
109 | 109 | self._normalized_timestamp = None |
110 | 110 | self._timestamp = timestamp |
121 | 121 | self._timestamp > self._UINT64_MAX): |
122 | 122 | return None |
123 | 123 | |
124 | timestamp, remainder = divmod(self._timestamp, self._100NS_PER_SECOND) | |
124 | timestamp, remainder = divmod( | |
125 | self._timestamp, self._100_NANOSECONDS_PER_SECOND) | |
125 | 126 | number_of_days, hours, minutes, seconds = self._GetTimeValues(timestamp) |
126 | 127 | |
127 | 128 | year, month, day_of_month = self._GetDateValuesWithEpoch( |
0 | # -*- coding: utf-8 -*- | |
1 | """Golang time.Time timestamp implementation.""" | |
2 | ||
3 | import decimal | |
4 | import struct | |
5 | ||
6 | from dfdatetime import definitions | |
7 | from dfdatetime import factory | |
8 | from dfdatetime import interface | |
9 | ||
10 | ||
11 | class GolangTimeEpoch(interface.DateTimeEpoch): | |
12 | """Golang time.Time epoch.""" | |
13 | ||
14 | def __init__(self): | |
15 | """Initializes a Golang time.Time epoch.""" | |
16 | super(GolangTimeEpoch, self).__init__(1, 1, 1) | |
17 | ||
18 | ||
19 | class GolangTime(interface.DateTimeValues): | |
20 | """Golang time.Time timestamp. | |
21 | ||
22 | A Golang time.Time timestamp contans the number of nanoseconds since | |
23 | January 1, 1 UTC. Depending on the version of the timestamp, the time | |
24 | zone is stored in minutes or seconds relative to UTC. | |
25 | ||
26 | A serialized version 1 Golang time.Time timestamp is a 15 byte value | |
27 | that consists of: | |
28 | ||
29 | * byte 0 - version as an 8-bit integer. | |
30 | * bytes 1-8 - number of seconds since January 1, 1 as a big-endian signed | |
31 | integer. | |
32 | * bytes 9-12 - fraction of second, number of nanoseconds as a big-endian | |
33 | signed integer. | |
34 | * bytes 13-14 - time zone offset in minutes as a 16-bit big endian integer, | |
35 | where -1 represents UTC. | |
36 | ||
37 | A serialized version 2 Golang time.Time timestamp is a 16 byte value | |
38 | that consists of: | |
39 | ||
40 | * byte 0 - version as an 8-bit integer. | |
41 | * bytes 1-8 - number of seconds since January 1, 1 as a big-endian signed | |
42 | integer. | |
43 | * bytes 9-12 - fraction of second, number of nanoseconds as a big-endian | |
44 | signed integer. | |
45 | * bytes 13-14 - time zone offset in minutes as a 16-bit big endian integer, | |
46 | where -1 represents UTC. | |
47 | * byte 15 - time zone offset in seconds as an 8-bit integer. | |
48 | ||
49 | Attributes: | |
50 | is_local_time (bool): True if the date and time value is in local time | |
51 | """ | |
52 | ||
53 | # The delta between January 1, 1970 (unix epoch) and January 1, 1 | |
54 | # (Golang epoch). | |
55 | _GOLANG_TO_POSIX_BASE = ( | |
56 | ((1969 * 365) + (1969 // 4) - (1969 // 100) + (1969 // 400)) * | |
57 | definitions.SECONDS_PER_DAY) | |
58 | ||
59 | _EPOCH = GolangTimeEpoch() | |
60 | ||
61 | def __init__(self, golang_timestamp=None): | |
62 | """Initializes a Golang time.Time timestamp. | |
63 | ||
64 | Args: | |
65 | golang_timestamp (Optional[bytes]): the Golang time.Time timestamp. | |
66 | """ | |
67 | number_of_seconds, nanoseconds, time_zone_offset = (None, None, None) | |
68 | if golang_timestamp is not None: | |
69 | number_of_seconds, nanoseconds, time_zone_offset = ( | |
70 | self._GetNumberOfSeconds(golang_timestamp)) | |
71 | ||
72 | super(GolangTime, self).__init__(time_zone_offset=time_zone_offset) | |
73 | self._golang_timestamp = golang_timestamp | |
74 | self._nanoseconds = nanoseconds | |
75 | self._number_of_seconds = number_of_seconds | |
76 | self._precision = definitions.PRECISION_1_NANOSECOND | |
77 | ||
78 | if time_zone_offset: | |
79 | self.is_local_time = True | |
80 | ||
81 | @property | |
82 | def golang_timestamp(self): | |
83 | """int: Golang time.Time timestamp or None if not set.""" | |
84 | return self._golang_timestamp | |
85 | ||
86 | def _GetNormalizedTimestamp(self): | |
87 | """Retrieves the normalized timestamp. | |
88 | ||
89 | Returns: | |
90 | decimal.Decimal: normalized timestamp, which contains the number of | |
91 | seconds since January 1, 1970 00:00:00 and a fraction of second used | |
92 | for increased precision, or None if the normalized timestamp cannot be | |
93 | determined. | |
94 | """ | |
95 | if self._normalized_timestamp is None: | |
96 | if (self._number_of_seconds is not None and | |
97 | self._number_of_seconds >= self._GOLANG_TO_POSIX_BASE and | |
98 | self._nanoseconds is not None and self._nanoseconds >= 0): | |
99 | ||
100 | self._normalized_timestamp = decimal.Decimal( | |
101 | self._number_of_seconds - GolangTime._GOLANG_TO_POSIX_BASE) | |
102 | ||
103 | if self._nanoseconds is not None and self._nanoseconds >= 0: | |
104 | self._normalized_timestamp += ( | |
105 | decimal.Decimal(self._nanoseconds) / | |
106 | definitions.NANOSECONDS_PER_SECOND) | |
107 | ||
108 | return self._normalized_timestamp | |
109 | ||
110 | def _GetNumberOfSeconds(self, golang_timestamp): | |
111 | """Retrieves the number of seconds from a Golang time.Time timestamp. | |
112 | ||
113 | Args: | |
114 | golang_timestamp (bytes): the Golang time.Time timestamp. | |
115 | ||
116 | Returns: | |
117 | tuple[int, int, int]: number of seconds since January 1, 1 00:00:00, | |
118 | fraction of second in nanoseconds and time zone offset in minutes. | |
119 | ||
120 | Raises: | |
121 | ValueError: if the Golang time.Time timestamp could not be parsed. | |
122 | """ | |
123 | byte_size = len(golang_timestamp) | |
124 | if byte_size < 15: | |
125 | raise ValueError('Unsupported Golang time.Time timestamp.') | |
126 | ||
127 | version = golang_timestamp[0] | |
128 | if version not in (1, 2): | |
129 | raise ValueError( | |
130 | 'Unsupported Golang time.Time timestamp version: {0:d}.'.format( | |
131 | version)) | |
132 | ||
133 | if (version == 1 and byte_size != 15) or (version == 2 and byte_size != 16): | |
134 | raise ValueError('Unsupported Golang time.Time timestamp.') | |
135 | ||
136 | try: | |
137 | number_of_seconds, nanoseconds, time_zone_offset = struct.unpack( | |
138 | '>qih', golang_timestamp[1:15]) | |
139 | ||
140 | # TODO: add support for version 2 time zone offset in seconds | |
141 | ||
142 | except struct.error as exception: | |
143 | raise ValueError(( | |
144 | 'Unable to unpacke Golang time.Time timestamp with error: ' | |
145 | '{0:s}').format(exception)) | |
146 | ||
147 | # A time zone offset of -1 minute is a special representation for UTC. | |
148 | if time_zone_offset == -1: | |
149 | time_zone_offset = 0 | |
150 | ||
151 | return number_of_seconds, nanoseconds, time_zone_offset | |
152 | ||
153 | def CopyFromDateTimeString(self, time_string): | |
154 | """Copies a date time value from a date and time string. | |
155 | ||
156 | Args: | |
157 | time_string (str): date and time value formatted as: | |
158 | YYYY-MM-DD hh:mm:ss.######[+-]##:## | |
159 | ||
160 | Where # are numeric digits ranging from 0 to 9 and the seconds | |
161 | fraction can be either 3 or 6 digits. The time of day, seconds | |
162 | fraction and time zone offset are optional. The default time zone | |
163 | is UTC. | |
164 | ||
165 | Raises: | |
166 | ValueError: if the time string is invalid or not supported. | |
167 | """ | |
168 | date_time_values = self._CopyDateTimeFromString(time_string) | |
169 | year = date_time_values.get('year', 0) | |
170 | month = date_time_values.get('month', 0) | |
171 | day_of_month = date_time_values.get('day_of_month', 0) | |
172 | hours = date_time_values.get('hours', 0) | |
173 | minutes = date_time_values.get('minutes', 0) | |
174 | seconds = date_time_values.get('seconds', 0) | |
175 | microseconds = date_time_values.get('microseconds', 0) | |
176 | time_zone_offset = date_time_values.get('time_zone_offset', 0) | |
177 | ||
178 | if year < 0: | |
179 | raise ValueError('Year value not supported: {0!s}.'.format(year)) | |
180 | ||
181 | seconds = self._GetNumberOfSecondsFromElements( | |
182 | year, month, day_of_month, hours, minutes, seconds) | |
183 | ||
184 | seconds += self._GOLANG_TO_POSIX_BASE | |
185 | nanoseconds = microseconds * definitions.NANOSECONDS_PER_MICROSECOND | |
186 | ||
187 | self._normalized_timestamp = None | |
188 | self._number_of_seconds = seconds | |
189 | self._nanoseconds = nanoseconds | |
190 | self._time_zone_offset = time_zone_offset | |
191 | ||
192 | def CopyToDateTimeString(self): | |
193 | """Copies the Golang time value to a date and time string. | |
194 | ||
195 | Returns: | |
196 | str: date and time value formatted as: "YYYY-MM-DD hh:mm:ss.######" or | |
197 | None if the timestamp cannot be copied to a date and time string. | |
198 | """ | |
199 | if self._number_of_seconds is None or self._number_of_seconds < 0: | |
200 | return None | |
201 | ||
202 | seconds = self._number_of_seconds | |
203 | nanoseconds_seconds, remainder = divmod( | |
204 | self._nanoseconds, definitions.NANOSECONDS_PER_SECOND) | |
205 | ||
206 | seconds += nanoseconds_seconds | |
207 | remainder = remainder // definitions.NANOSECONDS_PER_MICROSECOND | |
208 | number_of_days, hours, minutes, seconds = self._GetTimeValues(seconds) | |
209 | ||
210 | year, month, day_of_month = self._GetDateValuesWithEpoch( | |
211 | number_of_days, self._EPOCH) | |
212 | ||
213 | return '{0:04d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}.{6:06d}'.format( | |
214 | year, month, day_of_month, hours, minutes, seconds, remainder) | |
215 | ||
216 | ||
217 | factory.Factory.RegisterDateTimeValues(GolangTime) |
60 | 60 | |
61 | 61 | _EPOCH_NORMALIZED_TIME = NormalizedTimeEpoch() |
62 | 62 | |
63 | _100NS_PER_SECOND = 10000000 | |
64 | _100NS_PER_DECISECOND = 1000000 | |
65 | _100NS_PER_MILLISECOND = 10000 | |
66 | _100NS_PER_MICROSECOND = 10 | |
63 | _100_MILLISECONDS_PER_SECOND = 10 | |
64 | _100_NANOSECONDS_PER_SECOND = 10000000 | |
65 | _100_NANOSECONDS_PER_MICROSECOND = 10 | |
67 | 66 | |
68 | 67 | _INT64_MIN = -(1 << 63) |
69 | 68 | _INT64_MAX = (1 << 63) - 1 |
80 | 79 | from UTC or None if not set. |
81 | 80 | """ |
82 | 81 | super(DateTimeValues, self).__init__() |
82 | self._cached_date_time_values = None | |
83 | 83 | self._normalized_timestamp = None |
84 | 84 | self._precision = None |
85 | 85 | self._time_zone_offset = time_zone_offset |
601 | 601 | number_of_days, date_time_epoch.year, date_time_epoch.month, |
602 | 602 | date_time_epoch.day_of_month) |
603 | 603 | |
604 | def _GetDateWithTimeOfDay(self): | |
605 | """Retrieves the date with time of day. | |
606 | ||
607 | Note that the date and time are adjusted to UTC. | |
608 | ||
609 | Returns: | |
610 | tuple[int, int, int, int, int, int]: year, month, day of month, hours, | |
611 | minutes, seconds or (None, None, None, None, None, None) | |
612 | if the date and time values do not represent a date or time of day. | |
613 | """ | |
614 | normalized_timestamp = self._GetNormalizedTimestamp() | |
615 | if normalized_timestamp is None: | |
616 | return None, None, None, None, None, None | |
617 | ||
618 | if (not self._cached_date_time_values or | |
619 | self._cached_date_time_values[0] != normalized_timestamp): | |
620 | number_of_days, hours, minutes, seconds = self._GetTimeValues( | |
621 | normalized_timestamp) | |
622 | ||
623 | try: | |
624 | year, month, day_of_month = self._GetDateValuesWithEpoch( | |
625 | number_of_days, self._EPOCH_NORMALIZED_TIME) | |
626 | ||
627 | except ValueError: | |
628 | return None, None, None, None, None, None | |
629 | ||
630 | self._cached_date_time_values = ( | |
631 | normalized_timestamp, year, month, day_of_month, hours, minutes, | |
632 | seconds) | |
633 | ||
634 | return self._cached_date_time_values[1:] | |
635 | ||
604 | 636 | def _GetDayOfYear(self, year, month, day_of_month): |
605 | 637 | """Retrieves the day of the year for a specific day of a month in a year. |
606 | 638 | |
821 | 853 | |
822 | 854 | return int(normalized_timestamp) |
823 | 855 | |
856 | def CopyToPosixTimestampWithFractionOfSecond(self): | |
857 | """Copies the date time value to a POSIX timestamp with fraction of second. | |
858 | ||
859 | Returns: | |
860 | tuple[int, int]: a POSIX timestamp in seconds with fraction of second or | |
861 | None, None if no timestamp is available. | |
862 | """ | |
863 | normalized_timestamp = self._GetNormalizedTimestamp() | |
864 | if normalized_timestamp is None: | |
865 | return None, None | |
866 | ||
867 | remainder = None | |
868 | if self._precision == definitions.PRECISION_1_NANOSECOND: | |
869 | remainder = int( | |
870 | (normalized_timestamp % 1) * definitions.NANOSECONDS_PER_SECOND) | |
871 | elif self._precision == definitions.PRECISION_100_NANOSECONDS: | |
872 | remainder = int( | |
873 | (normalized_timestamp % 1) * self._100_NANOSECONDS_PER_SECOND) | |
874 | elif self._precision == definitions.PRECISION_1_MICROSECOND: | |
875 | remainder = int( | |
876 | (normalized_timestamp % 1) * definitions.MICROSECONDS_PER_SECOND) | |
877 | elif self._precision == definitions.PRECISION_1_MILLISECOND: | |
878 | remainder = int( | |
879 | (normalized_timestamp % 1) * definitions.MILLISECONDS_PER_SECOND) | |
880 | elif self._precision == definitions.PRECISION_100_MILLISECONDS: | |
881 | remainder = int( | |
882 | (normalized_timestamp % 1) * self._100_MILLISECONDS_PER_SECOND) | |
883 | ||
884 | return int(normalized_timestamp), remainder | |
885 | ||
824 | 886 | # TODO: remove this method when there is no more need for it in dfvfs. |
825 | 887 | def CopyToStatTimeTuple(self): |
826 | 888 | """Copies the date time value to a stat timestamp tuple. |
839 | 901 | definitions.PRECISION_1_MICROSECOND, |
840 | 902 | definitions.PRECISION_1_MILLISECOND, |
841 | 903 | definitions.PRECISION_100_MILLISECONDS): |
842 | remainder = int((normalized_timestamp % 1) * self._100NS_PER_SECOND) | |
904 | remainder = int( | |
905 | (normalized_timestamp % 1) * self._100_NANOSECONDS_PER_SECOND) | |
843 | 906 | |
844 | 907 | return int(normalized_timestamp), remainder |
845 | 908 | |
864 | 927 | date_time_string = self.CopyToDateTimeString() |
865 | 928 | if date_time_string: |
866 | 929 | date_time_string = date_time_string.replace(' ', 'T') |
867 | date_time_string = '{0:s}Z'.format(date_time_string) | |
930 | ||
931 | if self._time_zone_offset is not None or not self.is_local_time: | |
932 | time_zone_offset_hours, time_zone_offset_minutes = divmod( | |
933 | self._time_zone_offset or 0, 60) | |
934 | if time_zone_offset_hours > 0: | |
935 | time_zone_offset_sign = '-' | |
936 | else: | |
937 | time_zone_offset_sign = '+' | |
938 | time_zone_offset_hours *= -1 | |
939 | ||
940 | date_time_string = '{0:s}{1:s}{2:02d}:{3:02d}'.format( | |
941 | date_time_string, time_zone_offset_sign, time_zone_offset_hours, | |
942 | time_zone_offset_minutes) | |
943 | ||
868 | 944 | return date_time_string |
869 | 945 | |
870 | 946 | def GetDate(self): |
871 | 947 | """Retrieves the date represented by the date and time values. |
872 | 948 | |
949 | Note that the date is adjusted to UTC. | |
950 | ||
873 | 951 | Returns: |
874 | 952 | tuple[int, int, int]: year, month, day of month or (None, None, None) |
875 | 953 | if the date and time values do not represent a date. |
876 | 954 | """ |
877 | normalized_timestamp = self._GetNormalizedTimestamp() | |
878 | if normalized_timestamp is None: | |
879 | return None, None, None | |
880 | ||
881 | number_of_days, _, _, _ = self._GetTimeValues(normalized_timestamp) | |
882 | ||
883 | try: | |
884 | return self._GetDateValuesWithEpoch( | |
885 | number_of_days, self._EPOCH_NORMALIZED_TIME) | |
886 | ||
887 | except ValueError: | |
888 | return None, None, None | |
955 | year, month, day_of_month, _, _, _ = self._GetDateWithTimeOfDay() | |
956 | return year, month, day_of_month | |
889 | 957 | |
890 | 958 | def GetDateWithTimeOfDay(self): |
891 | 959 | """Retrieves the date with time of day. |
960 | ||
961 | Note that the date and time are adjusted to UTC. | |
892 | 962 | |
893 | 963 | Returns: |
894 | 964 | tuple[int, int, int, int, int, int]: year, month, day of month, hours, |
895 | 965 | minutes, seconds or (None, None, None, None, None, None) |
896 | 966 | if the date and time values do not represent a date or time of day. |
897 | 967 | """ |
898 | normalized_timestamp = self._GetNormalizedTimestamp() | |
899 | if normalized_timestamp is None: | |
900 | return None, None, None, None, None, None | |
901 | ||
902 | number_of_days, hours, minutes, seconds = self._GetTimeValues( | |
903 | normalized_timestamp) | |
904 | ||
905 | try: | |
906 | year, month, day_of_month = self._GetDateValuesWithEpoch( | |
907 | number_of_days, self._EPOCH_NORMALIZED_TIME) | |
908 | ||
909 | except ValueError: | |
910 | return None, None, None, None, None, None | |
911 | ||
912 | return year, month, day_of_month, hours, minutes, seconds | |
968 | return self._GetDateWithTimeOfDay() | |
913 | 969 | |
914 | 970 | # TODO: remove this method when there is no more need for it in plaso. |
915 | 971 | def GetPlasoTimestamp(self): |
916 | """Retrieves a timestamp that is compatible with plaso. | |
972 | """Retrieves a timestamp that is compatible with Plaso. | |
917 | 973 | |
918 | 974 | Returns: |
919 | 975 | int: a POSIX timestamp in microseconds or None if no timestamp is |
931 | 987 | def GetTimeOfDay(self): |
932 | 988 | """Retrieves the time of day represented by the date and time values. |
933 | 989 | |
990 | Note that the time is adjusted to UTC. | |
991 | ||
934 | 992 | Returns: |
935 | 993 | tuple[int, int, int]: hours, minutes, seconds or (None, None, None) |
936 | 994 | if the date and time values do not represent a time of day. |
937 | 995 | """ |
938 | normalized_timestamp = self._GetNormalizedTimestamp() | |
939 | if normalized_timestamp is None: | |
940 | return None, None, None | |
941 | ||
942 | _, hours, minutes, seconds = self._GetTimeValues(normalized_timestamp) | |
996 | _, _, _, hours, minutes, seconds = self._GetDateWithTimeOfDay() | |
943 | 997 | return hours, minutes, seconds |
26 | 26 | } |
27 | 27 | |
28 | 28 | Also see: |
29 | https://tools.ietf.org/html/rfc2579 | |
29 | https://datatracker.ietf.org/doc/html/rfc2579 | |
30 | 30 | |
31 | 31 | Attributes: |
32 | 32 | year (int): year, 0 through 65536. |
0 | # -*- coding: utf-8 -*- | |
1 | """The date and time values serializer.""" | |
2 | ||
3 | from dfdatetime import factory | |
4 | from dfdatetime import interface | |
5 | ||
6 | ||
7 | class Serializer(object): | |
8 | """Date and time values serializer.""" | |
9 | ||
10 | @classmethod | |
11 | def ConvertDictToDateTimeValues(cls, json_dict): | |
12 | """Converts a JSON dict into a date time values object. | |
13 | ||
14 | This method is deprecated use ConvertJSONToDateTimeValues instead. | |
15 | ||
16 | The dictionary of the JSON serialized objects consists of: | |
17 | { | |
18 | '__type__': 'DateTimeValues' | |
19 | '__class_name__': 'RFC2579DateTime' | |
20 | ... | |
21 | } | |
22 | ||
23 | Here '__type__' indicates the object base type. In this case this should | |
24 | be 'DateTimeValues'. The rest of the elements of the dictionary make up the | |
25 | date time values object properties. | |
26 | ||
27 | Args: | |
28 | json_dict (dict[str, object]): JSON serialized objects. | |
29 | ||
30 | Returns: | |
31 | dfdatetime.DateTimeValues: date and time values. | |
32 | """ | |
33 | return cls.ConvertJSONToDateTimeValues(json_dict) | |
34 | ||
35 | @classmethod | |
36 | def ConvertDateTimeValuesToDict(cls, date_time_values): | |
37 | """Converts a date and time values object into a JSON dictionary. | |
38 | ||
39 | This method is deprecated use ConvertDateTimeValuesToJSON instead. | |
40 | ||
41 | The resulting dictionary of the JSON serialized objects consists of: | |
42 | { | |
43 | '__type__': 'DateTimeValues' | |
44 | '__class_name__': 'RFC2579DateTime' | |
45 | ... | |
46 | } | |
47 | ||
48 | Here '__type__' indicates the object base type. In this case | |
49 | 'DateTimeValues'. The rest of the elements of the dictionary make up the | |
50 | date and time value object properties. | |
51 | ||
52 | Args: | |
53 | date_time_values (dfdatetime.DateTimeValues): date and time values. | |
54 | ||
55 | Returns: | |
56 | dict[str, object]: JSON serialized objects. | |
57 | ||
58 | Raises: | |
59 | TypeError: if object is not an instance of DateTimeValues. | |
60 | """ | |
61 | if not isinstance(date_time_values, interface.DateTimeValues): | |
62 | raise TypeError | |
63 | ||
64 | return cls.ConvertDateTimeValuesToJSON(date_time_values) | |
65 | ||
66 | @classmethod | |
67 | def ConvertDateTimeValuesToJSON(cls, date_time_values): | |
68 | """Converts a date and time values object into a JSON dictionary. | |
69 | ||
70 | The resulting dictionary of the JSON serialized objects consists of: | |
71 | { | |
72 | '__type__': 'DateTimeValues' | |
73 | '__class_name__': 'RFC2579DateTime' | |
74 | ... | |
75 | } | |
76 | ||
77 | Here '__type__' indicates the object base type. In this case | |
78 | 'DateTimeValues'. The rest of the elements of the dictionary make up the | |
79 | date and time value object properties. | |
80 | ||
81 | Args: | |
82 | date_time_values (dfdatetime.DateTimeValues): date and time values. | |
83 | ||
84 | Returns: | |
85 | dict[str, object]: JSON serialized objects. | |
86 | """ | |
87 | class_name = type(date_time_values).__name__ | |
88 | ||
89 | json_dict = { | |
90 | '__class_name__': class_name, | |
91 | '__type__': 'DateTimeValues'} | |
92 | ||
93 | if hasattr(date_time_values, 'timestamp'): | |
94 | json_dict['timestamp'] = date_time_values.timestamp | |
95 | ||
96 | elif hasattr(date_time_values, 'string'): | |
97 | json_dict['string'] = date_time_values.string | |
98 | ||
99 | elif class_name == 'FATDateTime': | |
100 | json_dict['fat_date_time'] = date_time_values.fat_date_time | |
101 | ||
102 | elif class_name == 'GolangTime': | |
103 | json_dict['golang_timestamp'] = date_time_values.golang_timestamp | |
104 | ||
105 | elif class_name == 'RFC2579DateTime': | |
106 | json_dict['rfc2579_date_time_tuple'] = ( | |
107 | date_time_values.year, date_time_values.month, | |
108 | date_time_values.day_of_month, date_time_values.hours, | |
109 | date_time_values.minutes, date_time_values.seconds, | |
110 | date_time_values.deciseconds) | |
111 | ||
112 | elif class_name == 'TimeElements': | |
113 | json_dict['time_elements_tuple'] = ( | |
114 | date_time_values.year, date_time_values.month, | |
115 | date_time_values.day_of_month, date_time_values.hours, | |
116 | date_time_values.minutes, date_time_values.seconds) | |
117 | ||
118 | elif class_name == 'TimeElementsInMilliseconds': | |
119 | json_dict['time_elements_tuple'] = ( | |
120 | date_time_values.year, date_time_values.month, | |
121 | date_time_values.day_of_month, date_time_values.hours, | |
122 | date_time_values.minutes, date_time_values.seconds, | |
123 | date_time_values.milliseconds) | |
124 | ||
125 | elif class_name == 'TimeElementsInMicroseconds': | |
126 | json_dict['time_elements_tuple'] = ( | |
127 | date_time_values.year, date_time_values.month, | |
128 | date_time_values.day_of_month, date_time_values.hours, | |
129 | date_time_values.minutes, date_time_values.seconds, | |
130 | date_time_values.microseconds) | |
131 | ||
132 | if date_time_values.time_zone_offset is not None: | |
133 | json_dict['time_zone_offset'] = date_time_values.time_zone_offset | |
134 | ||
135 | if date_time_values.is_local_time: | |
136 | json_dict['is_local_time'] = True | |
137 | ||
138 | return json_dict | |
139 | ||
140 | @classmethod | |
141 | def ConvertJSONToDateTimeValues(cls, json_dict): | |
142 | """Converts a JSON dict into a date time values object. | |
143 | ||
144 | The dictionary of the JSON serialized objects consists of: | |
145 | { | |
146 | '__type__': 'DateTimeValues' | |
147 | '__class_name__': 'RFC2579DateTime' | |
148 | ... | |
149 | } | |
150 | ||
151 | Here '__type__' indicates the object base type. In this case this should | |
152 | be 'DateTimeValues'. The rest of the elements of the dictionary make up the | |
153 | date time values object properties. | |
154 | ||
155 | Args: | |
156 | json_dict (dict[str, object]): JSON serialized objects. | |
157 | ||
158 | Returns: | |
159 | dfdatetime.DateTimeValues: date and time values. | |
160 | """ | |
161 | class_name = json_dict.get('__class_name__', None) | |
162 | if class_name: | |
163 | del json_dict['__class_name__'] | |
164 | ||
165 | # Remove the class type from the JSON dict since we cannot pass it. | |
166 | del json_dict['__type__'] | |
167 | ||
168 | is_local_time = json_dict.get('is_local_time', None) | |
169 | if is_local_time is not None: | |
170 | del json_dict['is_local_time'] | |
171 | ||
172 | if class_name in ('InvalidTime', 'Never', 'NotSet'): | |
173 | string = json_dict.get('string', None) | |
174 | if string is not None: | |
175 | del json_dict['string'] | |
176 | ||
177 | date_time = factory.Factory.NewDateTimeValues(class_name, **json_dict) | |
178 | if is_local_time: | |
179 | date_time.is_local_time = is_local_time | |
180 | ||
181 | return date_time |
378 | 378 | ValueError: if the time string is invalid or not supported. |
379 | 379 | """ |
380 | 380 | if time_string.endswith('Z'): |
381 | time_string = time_string[:-1] | |
381 | time_string = ''.join([time_string[:-1], '+00:00']) | |
382 | 382 | |
383 | 383 | time_string_length = len(time_string) |
384 | 384 |
68 | 68 | if (self._timestamp is not None and self._timestamp >= 0 and |
69 | 69 | self._timestamp <= self._UINT60_MAX): |
70 | 70 | self._normalized_timestamp = ( |
71 | decimal.Decimal(self._timestamp) / self._100NS_PER_SECOND) | |
71 | decimal.Decimal(self._timestamp) / self._100_NANOSECONDS_PER_SECOND) | |
72 | 72 | self._normalized_timestamp -= self._UUID_TO_POSIX_BASE |
73 | 73 | |
74 | 74 | if self._time_zone_offset: |
109 | 109 | timestamp += self._UUID_TO_POSIX_BASE |
110 | 110 | timestamp *= definitions.MICROSECONDS_PER_SECOND |
111 | 111 | timestamp += date_time_values.get('microseconds', 0) |
112 | timestamp *= self._100NS_PER_MICROSECOND | |
112 | timestamp *= self._100_NANOSECONDS_PER_MICROSECOND | |
113 | 113 | |
114 | 114 | self._normalized_timestamp = None |
115 | 115 | self._timestamp = timestamp |
126 | 126 | self._timestamp > self._UINT60_MAX): |
127 | 127 | return None |
128 | 128 | |
129 | timestamp, remainder = divmod(self._timestamp, self._100NS_PER_SECOND) | |
129 | timestamp, remainder = divmod( | |
130 | self._timestamp, self._100_NANOSECONDS_PER_SECOND) | |
130 | 131 | number_of_days, hours, minutes, seconds = self._GetTimeValues(timestamp) |
131 | 132 | |
132 | 133 | year, month, day_of_month = self._GetDateValuesWithEpoch( |
7 | 7 | description_short: Digital Forensics date and time (dfDateTime). |
8 | 8 | description_long: dfDateTime, or Digital Forensics date and time, provides date and time objects |
9 | 9 | to preserve accuracy and precision. |
10 | pypi_token: /FwQrmudDyj+Mu3DaxLEo23Y6/OEgdHJqyWyZTjkJKje8pxCOrUorN8ZlXRGXbd3UA60emClt0M+SI+xqyA/qkpqZTgd5CKohpVAGH2EfzRc/zwJSGJ4tmZmMVAG8ayk6N9zFxCeC+y0BgZPQnj/Eq/RfuS4YIuaKutIUa5gTMmhWpODFKGV/2Wx1w67xWxAoONfEC5j0Gu3R274SS7FfBb4qWyIiBIJMwHGjlgp1Onk8KlpCLauZv8/hGfQDmWEdZ+mjcsTYyQYr1xfr1/FjQ== | |
11 |
57 | 57 | # General information about the project. |
58 | 58 | # pylint: disable=redefined-builtin |
59 | 59 | project = 'dfDateTime' |
60 | copyright = 'The dfDateTime Project Authors' | |
60 | copyright = 'The dfDateTime authors' | |
61 | 61 | version = dfdatetime.__version__ |
62 | 62 | release = dfdatetime.__version__ |
63 | 63 |
0 | 0 | docutils |
1 | 1 | recommonmark |
2 | sphinx >= 2.0.1 | |
2 | sphinx >= 4.1.0 | |
3 | 3 | sphinx-markdown-tables |
4 | 4 | sphinx-rtd-theme >= 0.5.1 |
123 | 123 | |
124 | 124 | ### Also see |
125 | 125 | |
126 | * [Embarcadero: System.TDateTime](http://docwiki.embarcadero.com/Libraries/XE3/en/System.TDateTime) | |
126 | * [Embarcadero: System.TDateTime](https://docwiki.embarcadero.com/Libraries/XE3/en/System.TDateTime) | |
127 | 127 | |
128 | 128 | ## FAT date and time |
129 | 129 | ### Characteristics |
196 | 196 | |
197 | 197 | * [MSDN: FILETIME](https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime) |
198 | 198 | |
199 | ## Golang time.Time timestamp | |
200 | ||
201 | ### Characteristics | |
202 | ||
203 | Attribute | Description | |
204 | --- | --- | |
205 | Supported date range | 0001-01-01 00:00:00.0000000 through ... | |
206 | Storage granularity | 1 nanosecond | |
207 | Time zone | internally represented. | |
208 | ||
209 | The granularity of the time zone value depends on the version of the timestamp. | |
210 | Version 1 timestamps are stored in minutes and version 2 timestamps add a | |
211 | seconds component. *Note: Version 2 is currently not supported.* | |
212 | ||
213 | ### Format | |
214 | ||
215 | Offset | Size | Description | |
216 | --- | --- | --- | |
217 | 0 | 1 | version (known values are 1 or 2) | |
218 | 1 | 8 | seconds since January, 1, 1 stored as a 64-bit big-endian signed integer | |
219 | 9 | 4 | fraction of second, in nanoseconds stored as a 32-bit big-endian signed integer | |
220 | 13 | 2 | time zone offset in minutes as a 16-bit big-endian signed integer. | |
221 | 15 | 1 | time zone offset in seconds (only for version 2) | |
222 | ||
223 | A value of -1 is a special value when the Time instance is initialised as UTC | |
224 | (e.g. ```time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC)```). | |
225 | ||
226 | ### Also see | |
227 | ||
228 | * [Golang time.go](https://cs.opensource.google/go/go/+/master:src/time/time.go) | |
229 | ||
199 | 230 | ## HFS timestamp |
200 | 231 | |
201 | 232 | Sometimes a distinction is made between HFS and HFS+ timestamps is that the |
239 | 270 | --- | --- | --- |
240 | 271 | 0 | 8 | timestamp, integer value containing the number of milliseconds before (when negative) or after (when positive) 1970-01-01 00:00:00.000 (or POSIX or Unix epoch) |
241 | 272 | |
242 | ### Also see: | |
273 | ### Also see | |
243 | 274 | |
244 | 275 | * [Class java.util.Date](https://docs.oracle.com/javase/8/docs/api/java/util/Date.html) |
245 | 276 | |
317 | 348 | |
318 | 349 | ### Also see |
319 | 350 | |
320 | * [RFC2579](https://tools.ietf.org/html/rfc2579) | |
351 | * [RFC2579](https://datatracker.ietf.org/doc/html/rfc2579) | |
321 | 352 | |
322 | 353 | ## SYSTEMTIME |
323 | 354 | ### Characteristics |
349 | 380 | |
350 | 381 | * [MSDN: SYSTEMTIME](https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime) |
351 | 382 | |
383 | ## Time element strings | |
384 | ||
385 | ### ISO 8601 / RFC 3339 | |
386 | ||
387 | Example `2020-05-31T00:00:47.044800+00:00` | |
388 | ||
389 | ### RFC 822 | |
390 | ||
391 | Example `Tue, 15 Nov 94 08:12:31 GMT` | |
392 | ||
393 | ### RFC 1123 | |
394 | ||
395 | Example `Tue, 15 Nov 1994 08:12:31 GMT` | |
396 | ||
397 | ### RFC 2822 | |
398 | ||
399 | ### Also see | |
400 | ||
401 | * [RFC 822 - Date and time specification](https://datatracker.ietf.org/doc/html/rfc822#section-5) | |
402 | * [RFC 1123 - RFC-822 date and time specification](https://datatracker.ietf.org/doc/html/rfc1123#section-5) | |
403 | * [RFC 2822 - Date and time specification](https://datatracker.ietf.org/doc/html/rfc2822#section-3.3) | |
404 | * [RFC 3339 - Internet date/time format](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) | |
405 | ||
352 | 406 | ## UUID version 1 time |
353 | 407 | ### Characteristics |
354 | 408 | |
388 | 442 | |
389 | 443 | ### Also see |
390 | 444 | |
391 | * [Chromium source: time.h](https://chromium.googlesource.com/chromium/src/base/+/master/time/time.h#5) | |
445 | * [Chromium source: time.h](https://chromium.googlesource.com/chromium/src/base/+/refs/heads/main/time/time.h#5) |
75 | 75 | :undoc-members: |
76 | 76 | :show-inheritance: |
77 | 77 | |
78 | dfdatetime.golang\_time module | |
79 | ------------------------------ | |
80 | ||
81 | .. automodule:: dfdatetime.golang_time | |
82 | :members: | |
83 | :undoc-members: | |
84 | :show-inheritance: | |
85 | ||
78 | 86 | dfdatetime.hfs\_time module |
79 | 87 | --------------------------- |
80 | 88 | |
139 | 147 | :undoc-members: |
140 | 148 | :show-inheritance: |
141 | 149 | |
150 | dfdatetime.serializer module | |
151 | ---------------------------- | |
152 | ||
153 | .. automodule:: dfdatetime.serializer | |
154 | :members: | |
155 | :undoc-members: | |
156 | :show-inheritance: | |
157 | ||
142 | 158 | dfdatetime.systemtime module |
143 | 159 | ---------------------------- |
144 | 160 |
62 | 62 | ``` |
63 | 63 | set PYTHONPATH=. |
64 | 64 | |
65 | C:\Python38\python.exe tools\update.py --preset dfdatetime | |
65 | C:\Python3\python.exe tools\update.py --preset dfdatetime | |
66 | 66 | ``` |
1 | 1 | # -*- coding: utf-8 -*- |
2 | 2 | """Installation and deployment script.""" |
3 | 3 | |
4 | import os | |
5 | import pkg_resources | |
4 | 6 | import sys |
5 | 7 | |
6 | 8 | try: |
145 | 147 | python_spec_file.append(line) |
146 | 148 | |
147 | 149 | return python_spec_file |
150 | ||
151 | ||
152 | def parse_requirements_from_file(path): | |
153 | """Parses requirements from a requirements file. | |
154 | ||
155 | Args: | |
156 | path (str): path to the requirements file. | |
157 | ||
158 | Returns: | |
159 | list[str]: name and optional version information of the required packages. | |
160 | """ | |
161 | requirements = [] | |
162 | if os.path.isfile(path): | |
163 | with open(path, 'r') as file_object: | |
164 | file_contents = file_object.read() | |
165 | ||
166 | for requirement in pkg_resources.parse_requirements(file_contents): | |
167 | try: | |
168 | name = str(requirement.req) | |
169 | except AttributeError: | |
170 | name = str(requirement) | |
171 | ||
172 | if not name.startswith('pip '): | |
173 | requirements.append(name) | |
174 | ||
175 | return requirements | |
148 | 176 | |
149 | 177 | |
150 | 178 | dfdatetime_description = ( |
181 | 209 | ('share/doc/dfdatetime', [ |
182 | 210 | 'ACKNOWLEDGEMENTS', 'AUTHORS', 'LICENSE', 'README']), |
183 | 211 | ], |
212 | install_requires=parse_requirements_from_file('requirements.txt'), | |
213 | tests_require=parse_requirements_from_file('test_requirements.txt'), | |
184 | 214 | ) |
100 | 100 | cocoa_time_object = cocoa_time.CocoaTime(timestamp=395011845.546875) |
101 | 101 | |
102 | 102 | date_time_string = cocoa_time_object.CopyToDateTimeStringISO8601() |
103 | self.assertEqual(date_time_string, '2013-07-08T21:30:45.546875Z') | |
103 | self.assertEqual(date_time_string, '2013-07-08T21:30:45.546875+00:00') | |
104 | 104 | |
105 | 105 | def testGetDate(self): |
106 | 106 | """Tests the GetDate function.""" |
138 | 138 | timestamp=41443.8263953) |
139 | 139 | |
140 | 140 | date_time_string = delphi_date_time_object.CopyToDateTimeStringISO8601() |
141 | self.assertEqual(date_time_string, '2013-06-18T19:50:00.553919Z') | |
141 | self.assertEqual(date_time_string, '2013-06-18T19:50:00.553919+00:00') | |
142 | 142 | |
143 | 143 | def testGetDate(self): |
144 | 144 | """Tests the GetDate function.""" |
94 | 94 | fake_time_object.CopyFromDateTimeString('2010-08-12 21:06:31.546875') |
95 | 95 | |
96 | 96 | date_time_string = fake_time_object.CopyToDateTimeStringISO8601() |
97 | self.assertEqual(date_time_string, '2010-08-12T21:06:31.546875Z') | |
97 | self.assertEqual(date_time_string, '2010-08-12T21:06:31.546875+00:00') | |
98 | 98 | |
99 | 99 | def testGetDate(self): |
100 | 100 | """Tests the GetDate function.""" |
120 | 120 | fat_date_time_object = fat_date_time.FATDateTime(fat_date_time=0xa8d03d0c) |
121 | 121 | |
122 | 122 | date_time_string = fat_date_time_object.CopyToDateTimeStringISO8601() |
123 | self.assertEqual(date_time_string, '2010-08-12T21:06:32Z') | |
123 | self.assertEqual(date_time_string, '2010-08-12T21:06:32+00:00') | |
124 | 124 | |
125 | 125 | def testGetDate(self): |
126 | 126 | """Tests the GetDate function.""" |
100 | 100 | filetime_object = filetime.Filetime(timestamp=0x01cb3a623d0a17ce) |
101 | 101 | |
102 | 102 | date_time_string = filetime_object.CopyToDateTimeStringISO8601() |
103 | self.assertEqual(date_time_string, '2010-08-12T21:06:31.5468750Z') | |
103 | self.assertEqual(date_time_string, '2010-08-12T21:06:31.5468750+00:00') | |
104 | 104 | |
105 | 105 | def testGetDate(self): |
106 | 106 | """Tests the GetDate function.""" |
0 | # -*- coding: utf-8 -*- | |
1 | """Tests for the Golang time.Time timestamp implementation.""" | |
2 | ||
3 | import decimal | |
4 | import struct | |
5 | import unittest | |
6 | ||
7 | from dfdatetime import golang_time | |
8 | ||
9 | ||
10 | class GolangEpochTest(unittest.TestCase): | |
11 | """Test for the Golang time.Time epoch.""" | |
12 | ||
13 | def testInitialize(self): | |
14 | """Tests the __init__ function.""" | |
15 | golang_epoch = golang_time.GolangTimeEpoch() | |
16 | self.assertIsNotNone(golang_epoch) | |
17 | ||
18 | def testEpochDate(self): | |
19 | """Tests the Golang time.Time epoch properties.""" | |
20 | golang_epoch = golang_time.GolangTimeEpoch() | |
21 | self.assertEqual(golang_epoch.year, 1) | |
22 | self.assertEqual(golang_epoch.month, 1) | |
23 | self.assertEqual(golang_epoch.day_of_month, 1) | |
24 | ||
25 | ||
26 | class GolangTest(unittest.TestCase): | |
27 | """Tests for the Golang time.Time timestamp.""" | |
28 | ||
29 | # pylint: disable=protected-access | |
30 | ||
31 | def testProperties(self): | |
32 | """Tests the Golang time.Time timestamp properties.""" | |
33 | golang_timestamp = struct.pack('>Bqih', 1, 0, 0, -1) | |
34 | golang_time_object = golang_time.GolangTime( | |
35 | golang_timestamp=golang_timestamp) | |
36 | self.assertEqual(golang_time_object._number_of_seconds, 0) | |
37 | self.assertEqual(golang_time_object._nanoseconds, 0) | |
38 | self.assertEqual(golang_time_object.is_local_time, False) | |
39 | self.assertEqual(golang_time_object._time_zone_offset, 0) | |
40 | ||
41 | golang_timestamp = struct.pack( | |
42 | '>Bqih', 1, golang_time.GolangTime._GOLANG_TO_POSIX_BASE, 0, 1) | |
43 | golang_time_object = golang_time.GolangTime( | |
44 | golang_timestamp=golang_timestamp) | |
45 | self.assertEqual(golang_time_object._number_of_seconds, | |
46 | golang_time.GolangTime._GOLANG_TO_POSIX_BASE) | |
47 | self.assertEqual(golang_time_object._nanoseconds, 0) | |
48 | self.assertEqual(golang_time_object.is_local_time, True) | |
49 | self.assertEqual(golang_time_object._time_zone_offset, 1) | |
50 | ||
51 | golang_timestamp = bytes.fromhex('010000000e7791f70000000000ffff') | |
52 | golang_time_object = golang_time.GolangTime( | |
53 | golang_timestamp=golang_timestamp) | |
54 | self.assertEqual(golang_time_object._number_of_seconds, | |
55 | golang_time.GolangTime._GOLANG_TO_POSIX_BASE) | |
56 | self.assertEqual(golang_time_object._nanoseconds, 0) | |
57 | self.assertEqual(golang_time_object.is_local_time, False) | |
58 | self.assertEqual(golang_time_object._time_zone_offset, 0) | |
59 | ||
60 | def testGetNormalizedTimestamp(self): | |
61 | """Test the _GetNormalizedTimestamp function.""" | |
62 | golang_timestamp = bytes.fromhex('010000000000000000000000000000') | |
63 | golang_time_object = golang_time.GolangTime( | |
64 | golang_timestamp=golang_timestamp) | |
65 | ||
66 | normalized_timestamp = golang_time_object._GetNormalizedTimestamp() | |
67 | self.assertIsNone(normalized_timestamp) | |
68 | ||
69 | golang_timestamp = struct.pack('>Bqih', 1, 63772480949, 711098348, 0) | |
70 | golang_time_object = golang_time.GolangTime( | |
71 | golang_timestamp=golang_timestamp) | |
72 | ||
73 | normalized_timestamp = golang_time_object._GetNormalizedTimestamp() | |
74 | self.assertEqual( | |
75 | normalized_timestamp, decimal.Decimal('1636884149.711098348')) | |
76 | ||
77 | golang_timestamp = bytes.fromhex('010000000e7791f70000000000ffff') | |
78 | golang_time_object = golang_time.GolangTime( | |
79 | golang_timestamp=golang_timestamp) | |
80 | ||
81 | normalized_timestamp = golang_time_object._GetNormalizedTimestamp() | |
82 | self.assertEqual(normalized_timestamp, decimal.Decimal('0')) | |
83 | ||
84 | golang_timestamp = bytes.fromhex('010000000e7791f60000000000ffff') | |
85 | golang_time_object = golang_time.GolangTime( | |
86 | golang_timestamp=golang_timestamp) | |
87 | ||
88 | normalized_timestamp = golang_time_object._GetNormalizedTimestamp() | |
89 | self.assertIsNone(normalized_timestamp) | |
90 | ||
91 | def testGetNumberOfSeconds(self): | |
92 | """Test the _GetNumberOfSeconds function.""" | |
93 | golang_time_object = golang_time.GolangTime() | |
94 | ||
95 | golang_timestamp = bytes.fromhex('010000000000000002000000030004') | |
96 | number_of_seconds, nanoseconds, time_zone_offset = ( | |
97 | golang_time_object._GetNumberOfSeconds(golang_timestamp)) | |
98 | self.assertEqual(number_of_seconds, 2) | |
99 | self.assertEqual(nanoseconds, 3) | |
100 | self.assertEqual(time_zone_offset, 4) | |
101 | ||
102 | golang_timestamp = bytes.fromhex('02000000000000000500000006ffff08') | |
103 | number_of_seconds, nanoseconds, time_zone_offset = ( | |
104 | golang_time_object._GetNumberOfSeconds(golang_timestamp)) | |
105 | self.assertEqual(number_of_seconds, 5) | |
106 | self.assertEqual(nanoseconds, 6) | |
107 | self.assertEqual(time_zone_offset, 0) | |
108 | ||
109 | with self.assertRaises(ValueError): | |
110 | golang_timestamp = bytes.fromhex('0100') | |
111 | golang_time_object._GetNumberOfSeconds(golang_timestamp) | |
112 | ||
113 | with self.assertRaises(ValueError): | |
114 | golang_timestamp = bytes.fromhex('020000000000000000000000000000') | |
115 | golang_time_object._GetNumberOfSeconds(golang_timestamp) | |
116 | ||
117 | with self.assertRaises(ValueError): | |
118 | golang_timestamp = bytes.fromhex('ff0000000000000000000000000000') | |
119 | golang_time_object._GetNumberOfSeconds(golang_timestamp) | |
120 | ||
121 | def testCopyFromDateTimeString(self): | |
122 | """Tests the CopyFromDateTimeString function.""" | |
123 | golang_time_object = golang_time.GolangTime() | |
124 | ||
125 | golang_time_object.CopyFromDateTimeString('0001-01-01') | |
126 | self.assertEqual(golang_time_object._number_of_seconds, 0) | |
127 | self.assertEqual(golang_time_object._nanoseconds, 0) | |
128 | self.assertEqual(golang_time_object._time_zone_offset, 0) | |
129 | ||
130 | golang_time_object.CopyFromDateTimeString('0001-01-01 00:01:00') | |
131 | self.assertEqual(golang_time_object._number_of_seconds, 60) | |
132 | self.assertEqual(golang_time_object._nanoseconds, 0) | |
133 | self.assertEqual(golang_time_object._time_zone_offset, 0) | |
134 | ||
135 | golang_time_object.CopyFromDateTimeString('0001-01-01 00:00:00.000001') | |
136 | self.assertEqual(golang_time_object._number_of_seconds, 0) | |
137 | self.assertEqual(golang_time_object._nanoseconds, 1000) | |
138 | self.assertEqual(golang_time_object._time_zone_offset, 0) | |
139 | ||
140 | golang_time_object.CopyFromDateTimeString('2000-01-01') | |
141 | self.assertEqual(golang_time_object._number_of_seconds, 63082281600) | |
142 | self.assertEqual(golang_time_object._nanoseconds, 0) | |
143 | self.assertEqual(golang_time_object._time_zone_offset, 0) | |
144 | ||
145 | golang_time_object.CopyFromDateTimeString('2000-01-01 12:23:45.567890') | |
146 | self.assertEqual(golang_time_object._number_of_seconds, 63082326225) | |
147 | self.assertEqual(golang_time_object._nanoseconds, 567890000) | |
148 | self.assertEqual(golang_time_object._time_zone_offset, 0) | |
149 | ||
150 | golang_time_object.CopyFromDateTimeString( | |
151 | '2000-01-01 12:23:45.567890+01:00') | |
152 | self.assertEqual(golang_time_object._number_of_seconds, 63082326225) | |
153 | self.assertEqual(golang_time_object._nanoseconds, 567890000) | |
154 | self.assertEqual(golang_time_object._time_zone_offset, 60) | |
155 | ||
156 | def testCopyToDateTimeString(self): | |
157 | """Test the CopyToDateTimeString function.""" | |
158 | golang_timestamp = bytes.fromhex('010000000eafffe8d121d95050ffff') | |
159 | golang_time_object = golang_time.GolangTime( | |
160 | golang_timestamp=golang_timestamp) | |
161 | ||
162 | self.assertEqual(golang_time_object._number_of_seconds, 63082326225) | |
163 | self.assertEqual(golang_time_object._nanoseconds, 567890000) | |
164 | self.assertEqual(golang_time_object._time_zone_offset, 0) | |
165 | ||
166 | date_time_string = golang_time_object.CopyToDateTimeString() | |
167 | self.assertEqual(date_time_string, '2000-01-01 12:23:45.567890') | |
168 | ||
169 | golang_timestamp = bytes.fromhex('010000000eafffe8d10000ddd5ffff') | |
170 | golang_time_object = golang_time.GolangTime( | |
171 | golang_timestamp=golang_timestamp) | |
172 | ||
173 | self.assertEqual(golang_time_object._number_of_seconds, 63082326225) | |
174 | self.assertEqual(golang_time_object._nanoseconds, 56789) | |
175 | self.assertEqual(golang_time_object._time_zone_offset, 0) | |
176 | ||
177 | date_time_string = golang_time_object.CopyToDateTimeString() | |
178 | self.assertEqual(date_time_string, '2000-01-01 12:23:45.000056') |
105 | 105 | hfs_time_object = hfs_time.HFSTime(timestamp=3458215528) |
106 | 106 | |
107 | 107 | date_time_string = hfs_time_object.CopyToDateTimeStringISO8601() |
108 | self.assertEqual(date_time_string, '2013-08-01T15:25:28Z') | |
108 | self.assertEqual(date_time_string, '2013-08-01T15:25:28+00:00') | |
109 | 109 | |
110 | 110 | def testGetDate(self): |
111 | 111 | """Tests the GetDate function.""" |
83 | 83 | java_time_object = java_time.JavaTime(timestamp=1281643591546) |
84 | 84 | |
85 | 85 | date_time_string = java_time_object.CopyToDateTimeStringISO8601() |
86 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.546Z') | |
86 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.546+00:00') | |
87 | 87 | |
88 | 88 | def testGetDate(self): |
89 | 89 | """Tests the GetDate function.""" |
103 | 103 | timestamp=43044.480556) |
104 | 104 | |
105 | 105 | date_time_string = ole_automation_date_object.CopyToDateTimeStringISO8601() |
106 | self.assertEqual(date_time_string, '2017-11-05T11:32:00.038400Z') | |
106 | self.assertEqual(date_time_string, '2017-11-05T11:32:00.038400+00:00') | |
107 | 107 | |
108 | 108 | def testGetDate(self): |
109 | 109 | """Tests the GetDate function.""" |
92 | 92 | posix_time_object = posix_time.PosixTime(timestamp=1281643591) |
93 | 93 | |
94 | 94 | date_time_string = posix_time_object.CopyToDateTimeStringISO8601() |
95 | self.assertEqual(date_time_string, '2010-08-12T20:06:31Z') | |
95 | self.assertEqual(date_time_string, '2010-08-12T20:06:31+00:00') | |
96 | ||
97 | def testCopyToPosixTimestampWithFractionOfSecond(self): | |
98 | """Tests the CopyToPosixTimestampWithFractionOfSecond function.""" | |
99 | posix_time_object = posix_time.PosixTime(timestamp=1281643591) | |
100 | ||
101 | posix_timestamp, fraction_of_second = ( | |
102 | posix_time_object.CopyToPosixTimestampWithFractionOfSecond()) | |
103 | self.assertEqual(posix_timestamp, 1281643591) | |
104 | self.assertIsNone(fraction_of_second) | |
105 | ||
106 | posix_time_object = posix_time.PosixTime() | |
107 | ||
108 | posix_timestamp, fraction_of_second = ( | |
109 | posix_time_object.CopyToPosixTimestampWithFractionOfSecond()) | |
110 | self.assertIsNone(posix_timestamp) | |
111 | self.assertIsNone(fraction_of_second) | |
96 | 112 | |
97 | 113 | # TODO: remove this method when there is no more need for it in dfvfs. |
98 | 114 | def testCopyToStatTimeTuple(self): |
227 | 243 | timestamp=1281643591546) |
228 | 244 | |
229 | 245 | date_time_string = posix_time_object.CopyToDateTimeStringISO8601() |
230 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.546Z') | |
246 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.546+00:00') | |
247 | ||
248 | def testCopyToPosixTimestampWithFractionOfSecond(self): | |
249 | """Tests the CopyToPosixTimestampWithFractionOfSecond function.""" | |
250 | posix_time_object = posix_time.PosixTimeInMilliseconds( | |
251 | timestamp=1281643591546) | |
252 | ||
253 | posix_timestamp, fraction_of_second = ( | |
254 | posix_time_object.CopyToPosixTimestampWithFractionOfSecond()) | |
255 | self.assertEqual(posix_timestamp, 1281643591) | |
256 | self.assertEqual(fraction_of_second, 546) | |
257 | ||
258 | posix_time_object = posix_time.PosixTime() | |
259 | ||
260 | posix_timestamp, fraction_of_second = ( | |
261 | posix_time_object.CopyToPosixTimestampWithFractionOfSecond()) | |
262 | self.assertIsNone(posix_timestamp) | |
263 | self.assertIsNone(fraction_of_second) | |
231 | 264 | |
232 | 265 | # TODO: remove this method when there is no more need for it in dfvfs. |
233 | 266 | def testCopyToStatTimeTuple(self): |
366 | 399 | timestamp=1281643591546875) |
367 | 400 | |
368 | 401 | date_time_string = posix_time_object.CopyToDateTimeStringISO8601() |
369 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.546875Z') | |
402 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.546875+00:00') | |
403 | ||
404 | def testCopyToPosixTimestampWithFractionOfSecond(self): | |
405 | """Tests the CopyToPosixTimestampWithFractionOfSecond function.""" | |
406 | posix_time_object = posix_time.PosixTimeInMicroseconds( | |
407 | timestamp=1281643591546875) | |
408 | ||
409 | posix_timestamp, fraction_of_second = ( | |
410 | posix_time_object.CopyToPosixTimestampWithFractionOfSecond()) | |
411 | self.assertEqual(posix_timestamp, 1281643591) | |
412 | self.assertEqual(fraction_of_second, 546875) | |
413 | ||
414 | posix_time_object = posix_time.PosixTime() | |
415 | ||
416 | posix_timestamp, fraction_of_second = ( | |
417 | posix_time_object.CopyToPosixTimestampWithFractionOfSecond()) | |
418 | self.assertIsNone(posix_timestamp) | |
419 | self.assertIsNone(fraction_of_second) | |
370 | 420 | |
371 | 421 | # TODO: remove this method when there is no more need for it in dfvfs. |
372 | 422 | def testCopyToStatTimeTuple(self): |
507 | 557 | timestamp=1281643591987654321) |
508 | 558 | |
509 | 559 | date_time_string = posix_time_object.CopyToDateTimeStringISO8601() |
510 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.987654321Z') | |
560 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.987654321+00:00') | |
511 | 561 | |
512 | 562 | def testGetDate(self): |
513 | 563 | """Tests the GetDate function.""" |
222 | 222 | rfc2579_date_time_tuple=(2010, 8, 12, 20, 6, 31, 6, '+', 0, 0)) |
223 | 223 | |
224 | 224 | date_time_string = rfc2579_date_time_object.CopyToDateTimeStringISO8601() |
225 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.6Z') | |
225 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.6+00:00') | |
226 | 226 | |
227 | 227 | def testGetDate(self): |
228 | 228 | """Tests the GetDate function.""" |
84 | 84 | date_time_string = semantic_time_object.CopyToDateTimeStringISO8601() |
85 | 85 | self.assertIsNone(date_time_string) |
86 | 86 | |
87 | def testCopyToPosixTimestamp(self): | |
88 | """Tests the CopyToPosixTimestamp function.""" | |
89 | semantic_time_object = semantic_time.SemanticTime() | |
90 | ||
91 | posix_timestamp = semantic_time_object.CopyToPosixTimestamp() | |
92 | self.assertIsNone(posix_timestamp) | |
93 | ||
94 | def testCopyToPosixTimestampWithFractionOfSecond(self): | |
95 | """Tests the CopyToPosixTimestampWithFractionOfSecond function.""" | |
96 | semantic_time_object = semantic_time.SemanticTime() | |
97 | ||
98 | posix_timestamp, fraction_of_second = ( | |
99 | semantic_time_object.CopyToPosixTimestampWithFractionOfSecond()) | |
100 | self.assertIsNone(posix_timestamp) | |
101 | self.assertIsNone(fraction_of_second) | |
102 | ||
87 | 103 | def testCopyToStatTimeTuple(self): |
88 | 104 | """Tests the CopyToStatTimeTuple function.""" |
89 | 105 | semantic_time_object = semantic_time.SemanticTime() |
0 | #!/usr/bin/env python3 | |
1 | # -*- coding: utf-8 -*- | |
2 | """Tests for the date and time values serializer.""" | |
3 | ||
4 | import unittest | |
5 | ||
6 | from dfdatetime import fat_date_time | |
7 | from dfdatetime import golang_time | |
8 | from dfdatetime import posix_time | |
9 | from dfdatetime import rfc2579_date_time | |
10 | from dfdatetime import semantic_time | |
11 | from dfdatetime import serializer | |
12 | from dfdatetime import time_elements | |
13 | ||
14 | ||
15 | class SerializerTest(unittest.TestCase): | |
16 | """Tests for the date and time values serializer.""" | |
17 | ||
18 | def testConvertDateTimeValuesToJSON(self): | |
19 | """Test ConvertDateTimeValuesToJSON function.""" | |
20 | posix_time_object = posix_time.PosixTime(timestamp=1281643591) | |
21 | ||
22 | expected_json_dict = { | |
23 | '__class_name__': 'PosixTime', | |
24 | '__type__': 'DateTimeValues', | |
25 | 'timestamp': 1281643591} | |
26 | ||
27 | json_dict = serializer.Serializer.ConvertDateTimeValuesToJSON( | |
28 | posix_time_object) | |
29 | self.assertEqual(json_dict, expected_json_dict) | |
30 | ||
31 | posix_time_object.is_local_time = True | |
32 | ||
33 | expected_json_dict = { | |
34 | '__class_name__': 'PosixTime', | |
35 | '__type__': 'DateTimeValues', | |
36 | 'is_local_time': True, | |
37 | 'timestamp': 1281643591} | |
38 | ||
39 | json_dict = serializer.Serializer.ConvertDateTimeValuesToJSON( | |
40 | posix_time_object) | |
41 | self.assertEqual(json_dict, expected_json_dict) | |
42 | ||
43 | never_time_object = semantic_time.Never() | |
44 | ||
45 | expected_json_dict = { | |
46 | '__class_name__': 'Never', | |
47 | '__type__': 'DateTimeValues', | |
48 | 'string': 'Never'} | |
49 | ||
50 | json_dict = serializer.Serializer.ConvertDateTimeValuesToJSON( | |
51 | never_time_object) | |
52 | self.assertEqual(json_dict, expected_json_dict) | |
53 | ||
54 | fat_date_time_object = fat_date_time.FATDateTime(fat_date_time=0xa8d03d0c) | |
55 | ||
56 | expected_json_dict = { | |
57 | '__class_name__': 'FATDateTime', | |
58 | '__type__': 'DateTimeValues', | |
59 | 'fat_date_time': 2832219404} | |
60 | ||
61 | json_dict = serializer.Serializer.ConvertDateTimeValuesToJSON( | |
62 | fat_date_time_object) | |
63 | self.assertEqual(json_dict, expected_json_dict) | |
64 | ||
65 | golang_timestamp = bytes.fromhex('01000000000000000200000003ffff') | |
66 | golang_time_object = golang_time.GolangTime( | |
67 | golang_timestamp=golang_timestamp) | |
68 | ||
69 | expected_json_dict = { | |
70 | '__class_name__': 'GolangTime', | |
71 | '__type__': 'DateTimeValues', | |
72 | 'golang_timestamp': ( | |
73 | b'\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\xff\xff'), | |
74 | 'time_zone_offset': 0} | |
75 | ||
76 | json_dict = serializer.Serializer.ConvertDateTimeValuesToJSON( | |
77 | golang_time_object) | |
78 | self.assertEqual(json_dict, expected_json_dict) | |
79 | ||
80 | rfc2579_date_time_object = rfc2579_date_time.RFC2579DateTime( | |
81 | rfc2579_date_time_tuple=(2010, 8, 12, 20, 6, 31, 6, '+', 2, 0)) | |
82 | ||
83 | expected_json_dict = { | |
84 | '__class_name__': 'RFC2579DateTime', | |
85 | '__type__': 'DateTimeValues', | |
86 | 'rfc2579_date_time_tuple': (2010, 8, 12, 20, 6, 31, 6), | |
87 | 'time_zone_offset': 120} | |
88 | ||
89 | json_dict = serializer.Serializer.ConvertDateTimeValuesToJSON( | |
90 | rfc2579_date_time_object) | |
91 | self.assertEqual(json_dict, expected_json_dict) | |
92 | ||
93 | time_elements_object = time_elements.TimeElements( | |
94 | time_elements_tuple=(2010, 8, 12, 20, 6, 31)) | |
95 | ||
96 | expected_json_dict = { | |
97 | '__class_name__': 'TimeElements', | |
98 | '__type__': 'DateTimeValues', | |
99 | 'time_elements_tuple': (2010, 8, 12, 20, 6, 31)} | |
100 | ||
101 | json_dict = serializer.Serializer.ConvertDateTimeValuesToJSON( | |
102 | time_elements_object) | |
103 | self.assertEqual(json_dict, expected_json_dict) | |
104 | ||
105 | time_elements_object = time_elements.TimeElementsInMilliseconds( | |
106 | time_elements_tuple=(2010, 8, 12, 20, 6, 31, 546)) | |
107 | ||
108 | expected_json_dict = { | |
109 | '__class_name__': 'TimeElementsInMilliseconds', | |
110 | '__type__': 'DateTimeValues', | |
111 | 'time_elements_tuple': (2010, 8, 12, 20, 6, 31, 546)} | |
112 | ||
113 | json_dict = serializer.Serializer.ConvertDateTimeValuesToJSON( | |
114 | time_elements_object) | |
115 | self.assertEqual(json_dict, expected_json_dict) | |
116 | ||
117 | time_elements_object = time_elements.TimeElementsInMicroseconds( | |
118 | time_elements_tuple=(2010, 8, 12, 20, 6, 31, 429876)) | |
119 | ||
120 | expected_json_dict = { | |
121 | '__class_name__': 'TimeElementsInMicroseconds', | |
122 | '__type__': 'DateTimeValues', | |
123 | 'time_elements_tuple': (2010, 8, 12, 20, 6, 31, 429876)} | |
124 | ||
125 | json_dict = serializer.Serializer.ConvertDateTimeValuesToJSON( | |
126 | time_elements_object) | |
127 | self.assertEqual(json_dict, expected_json_dict) | |
128 | ||
129 | # TODO: add tests for ConvertJSONToDateTimeValues | |
130 | ||
131 | ||
132 | if __name__ == '__main__': | |
133 | unittest.main() |
178 | 178 | system_time_tuple=(2010, 8, 4, 12, 20, 6, 31, 142)) |
179 | 179 | |
180 | 180 | date_time_string = systemtime_object.CopyToDateTimeStringISO8601() |
181 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.142Z') | |
181 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.142+00:00') | |
182 | 182 | |
183 | 183 | def testGetDate(self): |
184 | 184 | """Tests the GetDate function.""" |
274 | 274 | time_tuple = time_elements_object._CopyTimeFromStringISO8601('2023.5') |
275 | 275 | self.assertEqual(time_tuple, expected_time_tuple) |
276 | 276 | |
277 | expected_time_tuple = (8, 4, 32, None, None) | |
278 | time_tuple = time_elements_object._CopyTimeFromStringISO8601('08:04:32Z') | |
279 | self.assertEqual(time_tuple, expected_time_tuple) | |
280 | ||
281 | 277 | expected_time_tuple = (20, 23, 56, None, None) |
282 | 278 | time_tuple = time_elements_object._CopyTimeFromStringISO8601('20:23:56') |
283 | 279 | self.assertEqual(time_tuple, expected_time_tuple) |
301 | 297 | '20:23:56.327124') |
302 | 298 | self.assertEqual(time_tuple, expected_time_tuple) |
303 | 299 | |
300 | expected_time_tuple = (8, 4, 32, None, 0) | |
301 | time_tuple = time_elements_object._CopyTimeFromStringISO8601('08:04:32Z') | |
302 | self.assertEqual(time_tuple, expected_time_tuple) | |
303 | ||
304 | expected_time_tuple = (8, 4, 32, None, 0) | |
305 | time_tuple = time_elements_object._CopyTimeFromStringISO8601( | |
306 | '08:04:32+00:00') | |
307 | self.assertEqual(time_tuple, expected_time_tuple) | |
308 | ||
304 | 309 | expected_time_tuple = (20, 23, 56, 327124, -300) |
305 | 310 | time_tuple = time_elements_object._CopyTimeFromStringISO8601( |
306 | 311 | '20:23:56.327124-05:00') |
517 | 522 | self.assertEqual(time_elements_object._time_zone_offset, 0) |
518 | 523 | |
519 | 524 | expected_time_elements_tuple = (2010, 8, 12, 21, 6, 31) |
520 | time_elements_object.CopyFromStringISO8601('2010-08-12T21:06:31Z') | |
525 | time_elements_object.CopyFromStringISO8601('2010-08-12T21:06:31+00:00') | |
521 | 526 | self.assertEqual( |
522 | 527 | time_elements_object._time_elements_tuple, expected_time_elements_tuple) |
523 | 528 | self.assertEqual(time_elements_object._number_of_seconds, 1281647191) |
561 | 566 | self.assertEqual(time_elements_object._time_zone_offset, 60) |
562 | 567 | |
563 | 568 | expected_time_elements_tuple = (2012, 3, 5, 20, 40, 0) |
564 | time_elements_object.CopyFromStringISO8601('2012-03-05T20:40:00.0000000Z') | |
569 | time_elements_object.CopyFromStringISO8601( | |
570 | '2012-03-05T20:40:00.0000000+00:00') | |
565 | 571 | self.assertEqual( |
566 | 572 | time_elements_object._time_elements_tuple, expected_time_elements_tuple) |
567 | 573 | self.assertEqual(time_elements_object._number_of_seconds, 1330980000) |
645 | 651 | time_elements_tuple=(2010, 8, 12, 20, 6, 31)) |
646 | 652 | |
647 | 653 | date_time_string = time_elements_object.CopyToDateTimeStringISO8601() |
648 | self.assertEqual(date_time_string, '2010-08-12T20:06:31Z') | |
654 | self.assertEqual(date_time_string, '2010-08-12T20:06:31+00:00') | |
655 | ||
656 | time_elements_object.is_local_time = True | |
657 | ||
658 | date_time_string = time_elements_object.CopyToDateTimeStringISO8601() | |
659 | self.assertEqual(date_time_string, '2010-08-12T20:06:31') | |
660 | ||
661 | time_elements_object = time_elements.TimeElements( | |
662 | time_elements_tuple=(2010, 8, 12, 20, 6, 31), | |
663 | time_zone_offset=-120) | |
664 | ||
665 | date_time_string = time_elements_object.CopyToDateTimeStringISO8601() | |
666 | self.assertEqual(date_time_string, '2010-08-12T20:06:31+02:00') | |
667 | ||
668 | time_elements_object = time_elements.TimeElements( | |
669 | time_elements_tuple=(2010, 8, 12, 20, 6, 31), | |
670 | time_zone_offset=300) | |
671 | ||
672 | date_time_string = time_elements_object.CopyToDateTimeStringISO8601() | |
673 | self.assertEqual(date_time_string, '2010-08-12T20:06:31-05:00') | |
649 | 674 | |
650 | 675 | def testCopyToPosixTimestamp(self): |
651 | 676 | """Tests the CopyToPosixTimestamp function.""" |
660 | 685 | posix_timestamp = time_elements_object.CopyToPosixTimestamp() |
661 | 686 | self.assertIsNone(posix_timestamp) |
662 | 687 | |
688 | def testCopyToPosixTimestampWithFractionOfSecond(self): | |
689 | """Tests the CopyToPosixTimestampWithFractionOfSecond function.""" | |
690 | time_elements_object = time_elements.TimeElements( | |
691 | time_elements_tuple=(2010, 8, 12, 20, 6, 31)) | |
692 | ||
693 | posix_timestamp, fraction_of_second = ( | |
694 | time_elements_object.CopyToPosixTimestampWithFractionOfSecond()) | |
695 | self.assertEqual(posix_timestamp, 1281643591) | |
696 | self.assertIsNone(fraction_of_second) | |
697 | ||
698 | time_elements_object = time_elements.TimeElements() | |
699 | ||
700 | posix_timestamp, fraction_of_second = ( | |
701 | time_elements_object.CopyToPosixTimestampWithFractionOfSecond()) | |
702 | self.assertIsNone(posix_timestamp) | |
703 | self.assertIsNone(fraction_of_second) | |
704 | ||
663 | 705 | def testGetDate(self): |
664 | 706 | """Tests the GetDate function.""" |
665 | 707 | time_elements_object = time_elements.TimeElements( |
852 | 894 | self.assertEqual(time_elements_object._time_zone_offset, 0) |
853 | 895 | |
854 | 896 | expected_time_elements_tuple = (2010, 8, 12, 21, 6, 31) |
855 | time_elements_object.CopyFromStringISO8601('2010-08-12T21:06:31Z') | |
897 | time_elements_object.CopyFromStringISO8601('2010-08-12T21:06:31+00:00') | |
856 | 898 | self.assertEqual( |
857 | 899 | time_elements_object._time_elements_tuple, expected_time_elements_tuple) |
858 | 900 | self.assertEqual(time_elements_object._number_of_seconds, 1281647191) |
902 | 944 | self.assertEqual(time_elements_object._time_zone_offset, 60) |
903 | 945 | |
904 | 946 | expected_time_elements_tuple = (2012, 3, 5, 20, 40, 0) |
905 | time_elements_object.CopyFromStringISO8601('2012-03-05T20:40:00.0000000Z') | |
947 | time_elements_object.CopyFromStringISO8601( | |
948 | '2012-03-05T20:40:00.0000000+00:00') | |
906 | 949 | self.assertEqual( |
907 | 950 | time_elements_object._time_elements_tuple, expected_time_elements_tuple) |
908 | 951 | self.assertEqual(time_elements_object._number_of_seconds, 1330980000) |
968 | 1011 | time_elements_tuple=(2010, 8, 12, 20, 6, 31, 429)) |
969 | 1012 | |
970 | 1013 | date_time_string = time_elements_object.CopyToDateTimeStringISO8601() |
971 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.429Z') | |
1014 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.429+00:00') | |
1015 | ||
1016 | def testCopyToPosixTimestamp(self): | |
1017 | """Tests the CopyToPosixTimestamp function.""" | |
1018 | time_elements_object = time_elements.TimeElementsInMilliseconds( | |
1019 | time_elements_tuple=(2010, 8, 12, 20, 6, 31, 429)) | |
1020 | ||
1021 | posix_timestamp = time_elements_object.CopyToPosixTimestamp() | |
1022 | self.assertEqual(posix_timestamp, 1281643591) | |
1023 | ||
1024 | time_elements_object = time_elements.TimeElements() | |
1025 | ||
1026 | posix_timestamp = time_elements_object.CopyToPosixTimestamp() | |
1027 | self.assertIsNone(posix_timestamp) | |
1028 | ||
1029 | def testCopyToPosixTimestampWithFractionOfSecond(self): | |
1030 | """Tests the CopyToPosixTimestampWithFractionOfSecond function.""" | |
1031 | time_elements_object = time_elements.TimeElementsInMilliseconds( | |
1032 | time_elements_tuple=(2010, 8, 12, 20, 6, 31, 429)) | |
1033 | ||
1034 | posix_timestamp, fraction_of_second = ( | |
1035 | time_elements_object.CopyToPosixTimestampWithFractionOfSecond()) | |
1036 | self.assertEqual(posix_timestamp, 1281643591) | |
1037 | self.assertEqual(fraction_of_second, 429) | |
1038 | ||
1039 | time_elements_object = time_elements.TimeElements() | |
1040 | ||
1041 | posix_timestamp, fraction_of_second = ( | |
1042 | time_elements_object.CopyToPosixTimestampWithFractionOfSecond()) | |
1043 | self.assertIsNone(posix_timestamp) | |
1044 | self.assertIsNone(fraction_of_second) | |
972 | 1045 | |
973 | 1046 | def testGetDate(self): |
974 | 1047 | """Tests the GetDate function.""" |
1163 | 1236 | self.assertEqual(time_elements_object._time_zone_offset, 0) |
1164 | 1237 | |
1165 | 1238 | expected_time_elements_tuple = (2010, 8, 12, 21, 6, 31) |
1166 | time_elements_object.CopyFromStringISO8601('2010-08-12T21:06:31Z') | |
1239 | time_elements_object.CopyFromStringISO8601('2010-08-12T21:06:31+00:00') | |
1167 | 1240 | self.assertEqual( |
1168 | 1241 | time_elements_object._time_elements_tuple, expected_time_elements_tuple) |
1169 | 1242 | self.assertEqual(time_elements_object._number_of_seconds, 1281647191) |
1213 | 1286 | self.assertEqual(time_elements_object._time_zone_offset, 60) |
1214 | 1287 | |
1215 | 1288 | expected_time_elements_tuple = (2012, 3, 5, 20, 40, 0) |
1216 | time_elements_object.CopyFromStringISO8601('2012-03-05T20:40:00.0000000Z') | |
1289 | time_elements_object.CopyFromStringISO8601( | |
1290 | '2012-03-05T20:40:00.0000000+00:00') | |
1217 | 1291 | self.assertEqual( |
1218 | 1292 | time_elements_object._time_elements_tuple, expected_time_elements_tuple) |
1219 | 1293 | self.assertEqual(time_elements_object._number_of_seconds, 1330980000) |
1279 | 1353 | time_elements_tuple=(2010, 8, 12, 20, 6, 31, 429876)) |
1280 | 1354 | |
1281 | 1355 | date_time_string = time_elements_object.CopyToDateTimeStringISO8601() |
1282 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.429876Z') | |
1356 | self.assertEqual(date_time_string, '2010-08-12T20:06:31.429876+00:00') | |
1357 | ||
1358 | def testCopyToPosixTimestamp(self): | |
1359 | """Tests the CopyToPosixTimestamp function.""" | |
1360 | time_elements_object = time_elements.TimeElementsInMicroseconds( | |
1361 | time_elements_tuple=(2010, 8, 12, 20, 6, 31, 429876)) | |
1362 | ||
1363 | posix_timestamp = time_elements_object.CopyToPosixTimestamp() | |
1364 | self.assertEqual(posix_timestamp, 1281643591) | |
1365 | ||
1366 | time_elements_object = time_elements.TimeElements() | |
1367 | ||
1368 | posix_timestamp = time_elements_object.CopyToPosixTimestamp() | |
1369 | self.assertIsNone(posix_timestamp) | |
1370 | ||
1371 | def testCopyToPosixTimestampWithFractionOfSecond(self): | |
1372 | """Tests the CopyToPosixTimestampWithFractionOfSecond function.""" | |
1373 | time_elements_object = time_elements.TimeElementsInMicroseconds( | |
1374 | time_elements_tuple=(2010, 8, 12, 20, 6, 31, 429876)) | |
1375 | ||
1376 | posix_timestamp, fraction_of_second = ( | |
1377 | time_elements_object.CopyToPosixTimestampWithFractionOfSecond()) | |
1378 | self.assertEqual(posix_timestamp, 1281643591) | |
1379 | self.assertEqual(fraction_of_second, 429876) | |
1380 | ||
1381 | time_elements_object = time_elements.TimeElements() | |
1382 | ||
1383 | posix_timestamp, fraction_of_second = ( | |
1384 | time_elements_object.CopyToPosixTimestampWithFractionOfSecond()) | |
1385 | self.assertIsNone(posix_timestamp) | |
1386 | self.assertIsNone(fraction_of_second) | |
1283 | 1387 | |
1284 | 1388 | def testGetDate(self): |
1285 | 1389 | """Tests the GetDate function.""" |
132 | 132 | uuid_time_object = uuid_time.UUIDTime(timestamp=uuid_object.time) |
133 | 133 | |
134 | 134 | date_time_string = uuid_time_object.CopyToDateTimeStringISO8601() |
135 | self.assertEqual(date_time_string, '2012-05-16T01:11:01.6544084Z') | |
135 | self.assertEqual(date_time_string, '2012-05-16T01:11:01.6544084+00:00') | |
136 | 136 | |
137 | 137 | def testGetDate(self): |
138 | 138 | """Tests the GetDate function.""" |
99 | 99 | webkit_time_object = webkit_time.WebKitTime(timestamp=12926120791546875) |
100 | 100 | |
101 | 101 | date_time_string = webkit_time_object.CopyToDateTimeStringISO8601() |
102 | self.assertEqual(date_time_string, '2010-08-12T21:06:31.546875Z') | |
102 | self.assertEqual(date_time_string, '2010-08-12T21:06:31.546875+00:00') | |
103 | 103 | |
104 | 104 | def testGetDate(self): |
105 | 105 | """Tests the GetDate function.""" |
0 | 0 | [tox] |
1 | envlist = py3{6,7,8,9},coverage,docs,pylint | |
1 | envlist = py3{6,7,8,9,10},coverage,docs,pylint | |
2 | 2 | |
3 | 3 | [testenv] |
4 | 4 | pip_pre = True |
9 | 9 | -rtest_requirements.txt |
10 | 10 | coverage: coverage |
11 | 11 | commands = |
12 | py3{6,7,8,9}: ./run_tests.py | |
12 | py3{6,7,8,9,10}: ./run_tests.py | |
13 | 13 | coverage: coverage erase |
14 | 14 | coverage: coverage run --source=dfdatetime --omit="*_test*,*__init__*,*test_lib*" run_tests.py |
15 | 15 | |
43 | 43 | deps = |
44 | 44 | -rrequirements.txt |
45 | 45 | -rtest_requirements.txt |
46 | pylint >= 2.6.0, < 2.7.0 | |
46 | pylint >= 2.9.0, < 2.10.0 | |
47 | 47 | commands = |
48 | 48 | pylint --version |
49 | 49 | # Ignore setup.py for now due to: |
24 | 24 | rpm_name (str): name of the rpm package that provides the dependency. |
25 | 25 | skip_check (bool): True if the dependency should be skipped by the |
26 | 26 | CheckDependencies or CheckTestDependencies methods of DependencyHelper. |
27 | skip_requires (bool): True if the dependency should be excluded from | |
28 | requirements.txt or setup.py install_requires. | |
27 | 29 | version_property (str): name of the version attribute or function. |
28 | 30 | """ |
29 | 31 | |
45 | 47 | self.python3_only = False |
46 | 48 | self.rpm_name = None |
47 | 49 | self.skip_check = None |
50 | self.skip_requires = None | |
48 | 51 | self.version_property = None |
49 | 52 | |
50 | 53 | |
62 | 65 | 'python3_only', |
63 | 66 | 'rpm_name', |
64 | 67 | 'skip_check', |
68 | 'skip_requires', | |
65 | 69 | 'version_property']) |
66 | 70 | |
67 | 71 | def _GetConfigValue(self, config_parser, section_name, value_name): |