Karol Sójko 3 роки тому
батько
коміт
565e890973

+ 31 - 11
.pnp.cjs

@@ -59,6 +59,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
       {\
         "name": "@standardnotes/syncing-server",\
         "reference": "workspace:packages/syncing-server"\
+      },\
+      {\
+        "name": "@standardnotes/time",\
+        "reference": "workspace:packages/time"\
       }\
     ],\
     "enableTopLevelFallback": true,\
@@ -74,7 +78,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
       ["@standardnotes/scheduler-server", ["workspace:packages/scheduler"]],\
       ["@standardnotes/security", ["workspace:packages/security"]],\
       ["@standardnotes/server-monorepo", ["workspace:."]],\
-      ["@standardnotes/syncing-server", ["workspace:packages/syncing-server"]]\
+      ["@standardnotes/syncing-server", ["workspace:packages/syncing-server"]],\
+      ["@standardnotes/time", ["workspace:packages/time"]]\
     ],\
     "fallbackPool": [\
     ],\
@@ -2682,7 +2687,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
             ["@standardnotes/domain-events", "workspace:packages/domain-events"],\
             ["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
             ["@standardnotes/security", "workspace:packages/security"],\
-            ["@standardnotes/time", "npm:1.7.1"],\
+            ["@standardnotes/time", "workspace:packages/time"],\
             ["@types/cors", "npm:2.8.12"],\
             ["@types/express", "npm:4.17.13"],\
             ["@types/ioredis", "npm:4.28.10"],\
@@ -2745,7 +2750,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
             ["@standardnotes/settings", "npm:1.15.0"],\
             ["@standardnotes/sncrypto-common", "npm:1.9.0"],\
             ["@standardnotes/sncrypto-node", "npm:1.8.3"],\
-            ["@standardnotes/time", "npm:1.7.1"],\
+            ["@standardnotes/time", "workspace:packages/time"],\
             ["@types/bcryptjs", "npm:2.4.2"],\
             ["@types/cors", "npm:2.8.12"],\
             ["@types/express", "npm:4.17.13"],\
@@ -2893,7 +2898,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
             ["@standardnotes/security", "workspace:packages/security"],\
             ["@standardnotes/sncrypto-common", "npm:1.9.0"],\
             ["@standardnotes/sncrypto-node", "npm:1.8.3"],\
-            ["@standardnotes/time", "npm:1.7.1"],\
+            ["@standardnotes/time", "workspace:packages/time"],\
             ["@types/connect-busboy", "npm:1.0.0"],\
             ["@types/cors", "npm:2.8.12"],\
             ["@types/express", "npm:4.17.13"],\
@@ -2998,7 +3003,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
             ["@standardnotes/domain-events", "workspace:packages/domain-events"],\
             ["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
             ["@standardnotes/predicates", "workspace:packages/predicates"],\
-            ["@standardnotes/time", "npm:1.7.1"],\
+            ["@standardnotes/time", "workspace:packages/time"],\
             ["@types/ioredis", "npm:4.28.10"],\
             ["@types/jest", "npm:28.1.4"],\
             ["@types/newrelic", "npm:7.0.3"],\
@@ -3125,7 +3130,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
             ["@standardnotes/responses", "npm:1.6.39"],\
             ["@standardnotes/security", "workspace:packages/security"],\
             ["@standardnotes/settings", "npm:1.15.0"],\
-            ["@standardnotes/time", "npm:1.7.1"],\
+            ["@standardnotes/time", "workspace:packages/time"],\
             ["@types/cors", "npm:2.8.12"],\
             ["@types/dotenv", "npm:8.2.0"],\
             ["@types/express", "npm:4.17.13"],\
@@ -3167,15 +3172,21 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
         }]\
       ]],\
       ["@standardnotes/time", [\
-        ["npm:1.7.1", {\
-          "packageLocation": "./.yarn/cache/@standardnotes-time-npm-1.7.1-e6859705d5-ccb9c4af73.zip/node_modules/@standardnotes/time/",\
+        ["workspace:packages/time", {\
+          "packageLocation": "./packages/time/",\
           "packageDependencies": [\
-            ["@standardnotes/time", "npm:1.7.1"],\
+            ["@standardnotes/time", "workspace:packages/time"],\
+            ["@types/jest", "npm:27.5.2"],\
+            ["@types/microtime", "npm:2.1.0"],\
+            ["@typescript-eslint/eslint-plugin", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:5.30.5"],\
             ["dayjs", "npm:1.11.3"],\
+            ["eslint-plugin-prettier", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.2.1"],\
+            ["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:27.5.1"],\
             ["microtime", "npm:3.1.0"],\
-            ["reflect-metadata", "npm:0.1.13"]\
+            ["reflect-metadata", "npm:0.1.13"],\
+            ["ts-jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:27.1.5"]\
           ],\
-          "linkType": "HARD"\
+          "linkType": "SOFT"\
         }]\
       ]],\
       ["@standardnotes/utils", [\
@@ -3510,6 +3521,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
           "linkType": "HARD"\
         }]\
       ]],\
+      ["@types/microtime", [\
+        ["npm:2.1.0", {\
+          "packageLocation": "./.yarn/cache/@types-microtime-npm-2.1.0-111ed89518-6c23131fe4.zip/node_modules/@types/microtime/",\
+          "packageDependencies": [\
+            ["@types/microtime", "npm:2.1.0"]\
+          ],\
+          "linkType": "HARD"\
+        }]\
+      ]],\
       ["@types/mime", [\
         ["npm:1.3.2", {\
           "packageLocation": "./.yarn/cache/@types-mime-npm-1.3.2-ea71878ab3-0493368244.zip/node_modules/@types/mime/",\

BIN
.yarn/cache/@standardnotes-time-npm-1.7.1-e6859705d5-ccb9c4af73.zip


BIN
.yarn/cache/@types-microtime-npm-2.1.0-111ed89518-6c23131fe4.zip


+ 1 - 1
packages/api-gateway/package.json

@@ -28,7 +28,7 @@
     "@standardnotes/domain-events": "workspace:*",
     "@standardnotes/domain-events-infra": "workspace:*",
     "@standardnotes/security": "workspace:*",
-    "@standardnotes/time": "^1.7.1",
+    "@standardnotes/time": "workspace:*",
     "aws-sdk": "^2.1160.0",
     "axios": "0.24.0",
     "cors": "2.8.5",

+ 1 - 1
packages/auth/package.json

@@ -45,7 +45,7 @@
     "@standardnotes/settings": "^1.15.0",
     "@standardnotes/sncrypto-common": "^1.9.0",
     "@standardnotes/sncrypto-node": "^1.8.3",
-    "@standardnotes/time": "^1.7.1",
+    "@standardnotes/time": "workspace:*",
     "aws-sdk": "^2.1159.0",
     "axios": "0.24.0",
     "bcryptjs": "2.4.3",

+ 1 - 1
packages/files/package.json

@@ -33,7 +33,7 @@
     "@standardnotes/security": "workspace:*",
     "@standardnotes/sncrypto-common": "^1.9.0",
     "@standardnotes/sncrypto-node": "^1.8.3",
-    "@standardnotes/time": "^1.7.1",
+    "@standardnotes/time": "workspace:*",
     "aws-sdk": "^2.1158.0",
     "connect-busboy": "^1.0.0",
     "cors": "^2.8.5",

+ 1 - 1
packages/scheduler/package.json

@@ -30,7 +30,7 @@
     "@standardnotes/domain-events": "workspace:*",
     "@standardnotes/domain-events-infra": "workspace:*",
     "@standardnotes/predicates": "workspace:*",
-    "@standardnotes/time": "^1.7.1",
+    "@standardnotes/time": "workspace:*",
     "aws-sdk": "^2.1158.0",
     "dayjs": "^1.11.3",
     "dotenv": "8.2.0",

+ 1 - 1
packages/syncing-server/package.json

@@ -34,7 +34,7 @@
     "@standardnotes/responses": "^1.6.39",
     "@standardnotes/security": "workspace:*",
     "@standardnotes/settings": "1.15.0",
-    "@standardnotes/time": "^1.7.1",
+    "@standardnotes/time": "workspace:*",
     "aws-sdk": "^2.1159.0",
     "axios": "0.24.0",
     "cors": "2.8.5",

+ 1 - 0
packages/time/.eslintignore

@@ -0,0 +1 @@
+dist

+ 6 - 0
packages/time/.eslintrc

@@ -0,0 +1,6 @@
+{
+  "extends": "../../.eslintrc",
+  "parserOptions": {
+    "project": "./linter.tsconfig.json"
+  }
+}

+ 182 - 0
packages/time/CHANGELOG.md

@@ -0,0 +1,182 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+
+## [1.7.2](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.7.1...@standardnotes/time@1.7.2) (2022-07-04)
+
+**Note:** Version bump only for package @standardnotes/time
+
+## [1.7.1](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.7.0...@standardnotes/time@1.7.1) (2022-06-23)
+
+### Bug Fixes
+
+* upgrade microtime package version ([65ec0e6](https://github.com/standardnotes/snjs/commit/65ec0e6f3a72718aa490f30a168fbdd13b5a4c76))
+
+# [1.7.0](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.6.10...@standardnotes/time@1.7.0) (2022-05-30)
+
+### Features
+
+* getting timestamp in seconds ([24c3215](https://github.com/standardnotes/snjs/commit/24c3215fd0797b60eec10a88583c0ed8c7020387))
+
+## [1.6.10](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.6.9...@standardnotes/time@1.6.10) (2022-05-30)
+
+### Bug Fixes
+
+* add converting string dates to seconds ([f1ccbc9](https://github.com/standardnotes/snjs/commit/f1ccbc929fbd9a452ca87cbaf88bf4ce30855c91))
+
+## [1.6.9](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.6.7...@standardnotes/time@1.6.9) (2022-05-04)
+
+**Note:** Version bump only for package @standardnotes/time
+
+## [1.6.8](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.6.7...@standardnotes/time@1.6.8) (2022-05-04)
+
+**Note:** Version bump only for package @standardnotes/time
+
+## [1.6.7](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.6.6...@standardnotes/time@1.6.7) (2022-04-22)
+
+**Note:** Version bump only for package @standardnotes/time
+
+## [1.6.6](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.6.5...@standardnotes/time@1.6.6) (2022-04-15)
+
+**Note:** Version bump only for package @standardnotes/time
+
+## [1.6.5](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.6.4...@standardnotes/time@1.6.5) (2022-04-11)
+
+**Note:** Version bump only for package @standardnotes/time
+
+## [1.6.4](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.6.3...@standardnotes/time@1.6.4) (2022-03-31)
+
+**Note:** Version bump only for package @standardnotes/time
+
+## [1.6.3](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.6.1...@standardnotes/time@1.6.3) (2022-02-28)
+
+### Bug Fixes
+
+* add pseudo change to get lerna to trigger ([41e6817](https://github.com/standardnotes/snjs/commit/41e6817bbf726b0932cdf16f58622328b9e42803))
+
+## [1.6.2](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.6.1...@standardnotes/time@1.6.2) (2022-02-28)
+
+### Bug Fixes
+
+* add pseudo change to get lerna to trigger ([41e6817](https://github.com/standardnotes/snjs/commit/41e6817bbf726b0932cdf16f58622328b9e42803))
+
+## [1.6.1](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.6.0...@standardnotes/time@1.6.1) (2022-02-10)
+
+### Bug Fixes
+
+* timer tests with utc dates ([c0b15a2](https://github.com/standardnotes/snjs/commit/c0b15a2ae45632615fa5e4064d5210bdd97ff237))
+
+# [1.6.0](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.5.0...@standardnotes/time@1.6.0) (2022-02-09)
+
+### Features
+
+* add date formatting ([4c65cb8](https://github.com/standardnotes/snjs/commit/4c65cb82b1acd842f7e35fb79389de95bef0ddcf))
+
+# [1.5.0](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.4.5...@standardnotes/time@1.5.0) (2022-02-09)
+
+### Features
+
+* add calculating time difference in days ([1348065](https://github.com/standardnotes/snjs/commit/1348065eb2bd7a559046a0f125751b32ad224d93))
+
+## [1.4.5](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.4.4...@standardnotes/time@1.4.5) (2021-12-29)
+
+**Note:** Version bump only for package @standardnotes/time
+
+## [1.4.4](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.4.3...@standardnotes/time@1.4.4) (2021-12-29)
+
+**Note:** Version bump only for package @standardnotes/time
+
+## [1.4.3](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.4.2...@standardnotes/time@1.4.3) (2021-12-29)
+
+**Note:** Version bump only for package @standardnotes/time
+
+## [1.4.2](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.4.1...@standardnotes/time@1.4.2) (2021-12-29)
+
+### Bug Fixes
+
+* remove code coverage reports from repository ([61f5dfd](https://github.com/standardnotes/snjs/commit/61f5dfd8e9698e36142df131ad210749865f70f4))
+
+## [1.4.1](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.4.0...@standardnotes/time@1.4.1) (2021-12-29)
+
+### Bug Fixes
+
+* correct gitignore paths ([cefc0cf](https://github.com/standardnotes/snjs/commit/cefc0cfcf98e3e5378e055b8c46931b53b23195e))
+* include dist in static components ([d17ce0f](https://github.com/standardnotes/snjs/commit/d17ce0f67045c6e4c97bf4577709aa58794e72e6))
+
+# 1.4.0 (2021-12-23)
+
+### Features
+
+* rename email backup setting to email backup frequency ([25e7b46](https://github.com/standardnotes/snjs/commit/25e7b4620834711ac7f513ae893898c5eab1af53))
+
+## 1.3.3 (2021-12-23)
+
+### Bug Fixes
+
+* lock package versions ([8aa2ce6](https://github.com/standardnotes/snjs/commit/8aa2ce676b57598ab72840adf851869d8e769022))
+
+## 1.3.2 (2021-12-23)
+
+### Bug Fixes
+
+* add publishing from package version by lerna ([80433d0](https://github.com/standardnotes/snjs/commit/80433d044f258095753482b8322d73aba3d9a9e4))
+
+## 1.3.1 (2021-12-23)
+
+### Bug Fixes
+
+* remove the ammend commit from lerna versioning ([f0400d9](https://github.com/standardnotes/snjs/commit/f0400d9a2f5a04eaece2e4c16da71166a2ddb251))
+
+# 1.3.0 (2021-12-23)
+
+### Features
+
+* add one drive backup frequency setting ([#522](https://github.com/standardnotes/snjs/issues/522)) ([c27827f](https://github.com/standardnotes/snjs/commit/c27827f8c7969dd32511c9c75122ece372132c83))
+
+## 1.2.4 (2021-12-23)
+
+### Bug Fixes
+
+* remove running tests upon deployment - ensured on PR status checks ([#523](https://github.com/standardnotes/snjs/issues/523)) ([5c795d1](https://github.com/standardnotes/snjs/commit/5c795d17b583d02955773576384e622c3ef7f418))
+
+## 1.2.3 (2021-12-23)
+
+### Bug Fixes
+
+* pr template ([#518](https://github.com/standardnotes/snjs/issues/518)) ([b445bb6](https://github.com/standardnotes/snjs/commit/b445bb64841217ae27c2514887629235be95d2a3))
+
+## 1.2.2 (2021-12-23)
+
+### Bug Fixes
+
+* checkout with personal access token ([773c1ef](https://github.com/standardnotes/snjs/commit/773c1ef91c4452ad411e928342060dcb59428e3c))
+
+## 1.2.1 (2021-12-22)
+
+### Bug Fixes
+
+* gpg signing with CI StandardNotes user ([d72f61c](https://github.com/standardnotes/snjs/commit/d72f61c23cd15b31d37340cc756d16526634b9ee))
+
+# [1.2.0](https://github.com/standardnotes/snjs/compare/@standardnotes/time@1.1.0...@standardnotes/time@1.2.0) (2021-12-22)
+
+### Features
+
+* add converting date to microseconds ([#516](https://github.com/standardnotes/snjs/issues/516)) ([a3dfd9e](https://github.com/standardnotes/snjs/commit/a3dfd9eccb275734ecd381cfb9fbb3fa132aa0ac))
+
+# 1.1.0 (2021-12-22)
+
+### Bug Fixes
+
+* add n days ahead method for timer ([#443](https://github.com/standardnotes/snjs/issues/443)) ([63926da](https://github.com/standardnotes/snjs/commit/63926da495c8b0fbaf1cddb595f7e2a90185b207))
+* timer specs ([e782a14](https://github.com/standardnotes/snjs/commit/e782a14b023954b1b9d112111d4bc15ed746a8ae))
+* versioning and package dependencies ([#509](https://github.com/standardnotes/snjs/issues/509)) ([fe1df94](https://github.com/standardnotes/snjs/commit/fe1df94eff3e90bcf9ba0cf45bdc44ac49204c71))
+
+### Features
+
+* add converting date to milliseconds ([#513](https://github.com/standardnotes/snjs/issues/513)) ([088bfcf](https://github.com/standardnotes/snjs/commit/088bfcf37ed98a5385735cd7c5ce8155bf276b16))
+* add method for getting n days ago date ([#434](https://github.com/standardnotes/snjs/issues/434)) ([4aa91c1](https://github.com/standardnotes/snjs/commit/4aa91c10a3612bff7f1c10a8660e1da4d5cbc492))
+* add n-hours ahead and ago methods for timer ([7ced52d](https://github.com/standardnotes/snjs/commit/7ced52db6dabccb8f1c203b73d6237be75ed4fb7))
+* add time package ([#311](https://github.com/standardnotes/snjs/issues/311)) ([f50d8aa](https://github.com/standardnotes/snjs/commit/f50d8aa11dd8c72f6ae03c281fc00a048937f623))
+* features instead of permissions ([#385](https://github.com/standardnotes/snjs/issues/385)) ([b53e967](https://github.com/standardnotes/snjs/commit/b53e967297bc472ed11aed79af79d0ae5b36d101))
+* upgrade node engine versions to latest active LTS ([#462](https://github.com/standardnotes/snjs/issues/462)) ([686fc15](https://github.com/standardnotes/snjs/commit/686fc15030d302b474ebb7ef1cd4dcc48ec42359))

+ 11 - 0
packages/time/jest.config.js

@@ -0,0 +1,11 @@
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+const base = require('../../jest.config');
+
+module.exports = {
+  ...base,
+  globals: {
+    'ts-jest': {
+      tsconfig: 'tsconfig.json',
+    },
+  }
+};

+ 4 - 0
packages/time/linter.tsconfig.json

@@ -0,0 +1,4 @@
+{
+  "extends": "./tsconfig.json",
+  "exclude": ["dist"]
+}

+ 39 - 0
packages/time/package.json

@@ -0,0 +1,39 @@
+{
+  "name": "@standardnotes/time",
+  "version": "1.8.0",
+  "engines": {
+    "node": ">=16.0.0 <17.0.0"
+  },
+  "description": "Utilities for time processing and calculation",
+  "main": "dist/src/index.js",
+  "types": "dist/src/index.d.ts",
+  "files": [
+    "dist/src/**/*.js",
+    "dist/src/**/*.d.ts"
+  ],
+  "publishConfig": {
+    "access": "public"
+  },
+  "author": "Standard Notes",
+  "license": "AGPL-3.0-or-later",
+  "scripts": {
+    "clean": "rm -fr dist",
+    "prebuild": "yarn clean",
+    "build": "tsc -p tsconfig.json",
+    "lint": "eslint . --ext .ts",
+    "test:unit": "jest spec --coverage"
+  },
+  "dependencies": {
+    "dayjs": "^1.10.8",
+    "microtime": "^3.1.0",
+    "reflect-metadata": "^0.1.13"
+  },
+  "devDependencies": {
+    "@types/jest": "^27.4.1",
+    "@types/microtime": "^2.1.0",
+    "@typescript-eslint/eslint-plugin": "^5.30.0",
+    "eslint-plugin-prettier": "^4.2.1",
+    "jest": "^27.5.1",
+    "ts-jest": "^27.1.3"
+  }
+}

+ 4 - 0
packages/time/src/Domain/Time/Time.ts

@@ -0,0 +1,4 @@
+export enum Time {
+  MicrosecondsInASecond = 1_000_000,
+  MicrosecondsInAMillisecond = 1_000,
+}

+ 111 - 0
packages/time/src/Domain/Time/Timer.spec.ts

@@ -0,0 +1,111 @@
+import 'reflect-metadata'
+
+import { Timer } from './Timer'
+
+describe('Timer', () => {
+  const createTimer = () => new Timer()
+
+  it('should return a timestamp in microseconds', () => {
+    const timestamp = createTimer().getTimestampInMicroseconds()
+    expect(`${timestamp}`.length).toEqual(16)
+  })
+
+  it('should return a timestamp in seconds', () => {
+    const timestamp = createTimer().getTimestampInSeconds()
+    expect(`${timestamp}`.length).toEqual(10)
+  })
+
+  it('should return a utc date', () => {
+    const date = createTimer().getUTCDate()
+    expect(date).toBeInstanceOf(Date)
+  })
+
+  it('should return a utc date n days ago', () => {
+    const date = createTimer().getUTCDate()
+    const dateNDaysAgo = createTimer().getUTCDateNDaysAgo(4)
+
+    expect(+date - +dateNDaysAgo >= 4 * 24 * 3600).toBeTruthy()
+  })
+
+  it('should return a utc date n days ahead', () => {
+    const date = createTimer().getUTCDate()
+    const dateNDaysAhead = createTimer().getUTCDateNDaysAhead(4)
+
+    expect(+dateNDaysAhead - +date >= 4 * 24 * 3600).toBeTruthy()
+  })
+
+  it('should calculate days difference between now and a given date', () => {
+    const dateNDaysAgo = createTimer().getUTCDateNDaysAgo(4)
+
+    expect(createTimer().dateWasNDaysAgo(dateNDaysAgo)).toEqual(4)
+  })
+
+  it('should return a utc date n hours ago', () => {
+    const date = createTimer().getUTCDate()
+    const dateNHoursAgo = createTimer().getUTCDateNHoursAgo(4)
+
+    expect(+date - +dateNHoursAgo >= 4 * 3600).toBeTruthy()
+  })
+
+  it('should return a utc date n hours ahead', () => {
+    const date = createTimer().getUTCDate()
+    const dateNHoursAhead = createTimer().getUTCDateNHoursAhead(4)
+
+    expect(+dateNHoursAhead - +date >= 4 * 3600).toBeTruthy()
+  })
+
+  it('should convert a date to milliseconds', () => {
+    const timestamp = createTimer().convertDateToMilliseconds(new Date(Date.UTC(2021, 2, 29, 12, 13, 45)))
+    expect(timestamp).toEqual(1617020025000)
+  })
+
+  it('should convert a date to microseconds', () => {
+    const timestamp = createTimer().convertDateToMicroseconds(new Date(Date.UTC(2021, 2, 29, 8, 0, 5, 233)))
+    expect(timestamp).toEqual(1617004805000000)
+  })
+
+  it('should convert a date to iso string', () => {
+    const isoString = createTimer().convertDateToISOString(new Date(Date.UTC(2021, 2, 29, 8, 0, 5)))
+    expect(isoString).toEqual('2021-03-29T08:00:05.000Z')
+  })
+
+  it('should convert a string date to microseconds', () => {
+    const timestamp = createTimer().convertStringDateToMicroseconds('2021-03-29 08:00:05.233Z')
+    expect(timestamp).toEqual(1617004805233000)
+  })
+
+  it('should convert a string date to seconds', () => {
+    const timestamp = createTimer().convertStringDateToSeconds('2021-03-29 08:00:05.233Z')
+    expect(timestamp).toEqual(1617004805)
+  })
+
+  it('should convert microseconds to string date', () => {
+    expect(createTimer().convertMicrosecondsToStringDate(1617004805233123)).toEqual('2021-03-29T08:00:05.233123Z')
+  })
+
+  it('should convert a string date to milliseconds', () => {
+    const timestamp = createTimer().convertStringDateToMilliseconds('Mon Mar 29 2021 12:13:45 GMT+0200')
+    expect(timestamp).toEqual(1617012825000)
+  })
+
+  it('should convert a string date to date', () => {
+    const date = createTimer().convertStringDateToDate('Mon Mar 29 2021 12:13:45 GMT+0200')
+    expect(date).toEqual(new Date(1617012825000))
+  })
+
+  it('should convert microseconds to date', () => {
+    expect(createTimer().convertMicrosecondsToDate(1617004805233123)).toEqual(new Date('2021-03-29T08:00:05.233123Z'))
+  })
+
+  it('should convert microseconds to milliseconds', () => {
+    expect(createTimer().convertMicrosecondsToMilliseconds(1616164633241312)).toEqual(1616164633241)
+  })
+
+  it('should convert microseconds to seconds', () => {
+    expect(createTimer().convertMicrosecondsToSeconds(1616164633241312)).toEqual(1616164633)
+  })
+
+  it('should format date', () => {
+    expect(createTimer().formatDate(new Date('2021-03-29T08:00:05.233123Z'), 'YYYY-MM-DD')).toEqual('2021-03-29')
+  })
+})

+ 95 - 0
packages/time/src/Domain/Time/Timer.ts

@@ -0,0 +1,95 @@
+import * as dayjs from 'dayjs'
+import * as utc from 'dayjs/plugin/utc'
+import * as microtime from 'microtime'
+import { Time } from './Time'
+import { TimerInterface } from './TimerInterface'
+
+export class Timer implements TimerInterface {
+  constructor() {
+    dayjs.extend(utc)
+  }
+
+  formatDate(date: Date, format: string): string {
+    return dayjs.utc(date).format(format)
+  }
+
+  convertDateToMilliseconds(date: Date): number {
+    return this.convertStringDateToMilliseconds(date.toString())
+  }
+
+  convertDateToMicroseconds(date: Date): number {
+    return this.convertStringDateToMicroseconds(date.toString())
+  }
+
+  convertMicrosecondsToSeconds(microseconds: number): number {
+    return Math.floor(microseconds / Time.MicrosecondsInASecond)
+  }
+
+  getTimestampInMicroseconds(): number {
+    return microtime.now()
+  }
+
+  getTimestampInSeconds(): number {
+    return this.convertMicrosecondsToSeconds(this.getTimestampInMicroseconds())
+  }
+
+  getUTCDate(): Date {
+    return dayjs.utc().toDate()
+  }
+
+  getUTCDateNDaysAgo(n: number): Date {
+    return dayjs.utc().subtract(n, 'days').toDate()
+  }
+
+  getUTCDateNDaysAhead(n: number): Date {
+    return dayjs.utc().add(n, 'days').toDate()
+  }
+
+  getUTCDateNHoursAgo(n: number): Date {
+    return dayjs.utc().subtract(n, 'hours').toDate()
+  }
+
+  getUTCDateNHoursAhead(n: number): Date {
+    return dayjs.utc().add(n, 'hours').toDate()
+  }
+
+  convertStringDateToDate(date: string): Date {
+    return dayjs.utc(date).toDate()
+  }
+
+  convertDateToISOString(date: Date): string {
+    return dayjs.utc(date).toISOString()
+  }
+
+  dateWasNDaysAgo(date: Date): number {
+    return dayjs.utc().diff(date, 'days')
+  }
+
+  convertStringDateToMicroseconds(date: string): number {
+    return this.convertStringDateToMilliseconds(date) * Time.MicrosecondsInAMillisecond
+  }
+
+  convertStringDateToMilliseconds(date: string): number {
+    return dayjs.utc(date).valueOf()
+  }
+
+  convertStringDateToSeconds(date: string): number {
+    return this.convertMicrosecondsToSeconds(this.convertStringDateToMicroseconds(date))
+  }
+
+  convertMicrosecondsToMilliseconds(microseconds: number): number {
+    return Math.floor(microseconds / Time.MicrosecondsInAMillisecond)
+  }
+
+  convertMicrosecondsToStringDate(microseconds: number): string {
+    const milliseconds = this.convertMicrosecondsToMilliseconds(microseconds)
+
+    const microsecondsString = microseconds.toString().substring(13)
+
+    return dayjs.utc(milliseconds).format(`YYYY-MM-DDTHH:mm:ss.SSS${microsecondsString}[Z]`)
+  }
+
+  convertMicrosecondsToDate(microseconds: number): Date {
+    return this.convertStringDateToDate(this.convertMicrosecondsToStringDate(microseconds))
+  }
+}

+ 22 - 0
packages/time/src/Domain/Time/TimerInterface.ts

@@ -0,0 +1,22 @@
+export interface TimerInterface {
+  getTimestampInMicroseconds(): number
+  getTimestampInSeconds(): number
+  getUTCDate(): Date
+  getUTCDateNDaysAgo(n: number): Date
+  getUTCDateNDaysAhead(n: number): Date
+  getUTCDateNHoursAgo(n: number): Date
+  getUTCDateNHoursAhead(n: number): Date
+  convertDateToMilliseconds(date: Date): number
+  convertDateToMicroseconds(date: Date): number
+  convertDateToISOString(date: Date): string
+  convertStringDateToDate(date: string): Date
+  convertStringDateToMicroseconds(date: string): number
+  convertStringDateToMilliseconds(date: string): number
+  convertStringDateToSeconds(date: string): number
+  convertMicrosecondsToMilliseconds(microseconds: number): number
+  convertMicrosecondsToSeconds(microseconds: number): number
+  convertMicrosecondsToStringDate(microseconds: number): string
+  convertMicrosecondsToDate(microseconds: number): Date
+  formatDate(date: Date, format: string): string
+  dateWasNDaysAgo(date: Date): number
+}

+ 3 - 0
packages/time/src/Domain/index.ts

@@ -0,0 +1,3 @@
+export * from './Time/Time'
+export * from './Time/Timer'
+export * from './Time/TimerInterface'

+ 1 - 0
packages/time/src/index.ts

@@ -0,0 +1 @@
+export * from './Domain'

+ 11 - 0
packages/time/tsconfig.json

@@ -0,0 +1,11 @@
+{
+  "extends": "../../tsconfig.json",
+  "compilerOptions": {
+    "composite": true,
+    "outDir": "./dist",
+  },
+  "include": [
+    "src/**/*"
+  ],
+  "references": []
+}

+ 3 - 0
tsconfig.json

@@ -51,6 +51,9 @@
     },
     {
       "path": "./packages/syncing-server"
+    },
+    {
+      "path": "./packages/time"
     }
   ]
 }

+ 23 - 11
yarn.lock

@@ -1964,7 +1964,7 @@ __metadata:
     "@standardnotes/domain-events": "workspace:*"
     "@standardnotes/domain-events-infra": "workspace:*"
     "@standardnotes/security": "workspace:*"
-    "@standardnotes/time": ^1.7.1
+    "@standardnotes/time": "workspace:*"
     "@types/cors": ^2.8.9
     "@types/express": ^4.17.11
     "@types/ioredis": ^4.28.10
@@ -2028,7 +2028,7 @@ __metadata:
     "@standardnotes/settings": ^1.15.0
     "@standardnotes/sncrypto-common": ^1.9.0
     "@standardnotes/sncrypto-node": ^1.8.3
-    "@standardnotes/time": ^1.7.1
+    "@standardnotes/time": "workspace:*"
     "@types/bcryptjs": ^2.4.2
     "@types/cors": ^2.8.9
     "@types/express": ^4.17.11
@@ -2175,7 +2175,7 @@ __metadata:
     "@standardnotes/security": "workspace:*"
     "@standardnotes/sncrypto-common": ^1.9.0
     "@standardnotes/sncrypto-node": ^1.8.3
-    "@standardnotes/time": ^1.7.1
+    "@standardnotes/time": "workspace:*"
     "@types/connect-busboy": ^1.0.0
     "@types/cors": ^2.8.9
     "@types/express": ^4.17.11
@@ -2273,7 +2273,7 @@ __metadata:
     "@standardnotes/domain-events": "workspace:*"
     "@standardnotes/domain-events-infra": "workspace:*"
     "@standardnotes/predicates": "workspace:*"
-    "@standardnotes/time": ^1.7.1
+    "@standardnotes/time": "workspace:*"
     "@types/ioredis": ^4.28.10
     "@types/jest": ^28.1.2
     "@types/newrelic": ^7.0.3
@@ -2388,7 +2388,7 @@ __metadata:
     "@standardnotes/responses": ^1.6.39
     "@standardnotes/security": "workspace:*"
     "@standardnotes/settings": 1.15.0
-    "@standardnotes/time": ^1.7.1
+    "@standardnotes/time": "workspace:*"
     "@types/cors": ^2.8.9
     "@types/dotenv": ^8.2.0
     "@types/express": ^4.17.9
@@ -2428,16 +2428,21 @@ __metadata:
   languageName: unknown
   linkType: soft
 
-"@standardnotes/time@npm:^1.7.1":
-  version: 1.7.1
-  resolution: "@standardnotes/time@npm:1.7.1"
+"@standardnotes/time@workspace:*, @standardnotes/time@workspace:packages/time":
+  version: 0.0.0-use.local
+  resolution: "@standardnotes/time@workspace:packages/time"
   dependencies:
+    "@types/jest": ^27.4.1
+    "@types/microtime": ^2.1.0
+    "@typescript-eslint/eslint-plugin": ^5.30.0
     dayjs: ^1.10.8
+    eslint-plugin-prettier: ^4.2.1
+    jest: ^27.5.1
     microtime: ^3.1.0
     reflect-metadata: ^0.1.13
-  checksum: ccb9c4af73d2c77d5b1cfea480930e3a30e87fb426eee3c60eb0ce0f259fa5c1f9b1b29fdc52c72d321821791e3bdc141e4af0bfc668662863012743332c5407
-  languageName: node
-  linkType: hard
+    ts-jest: ^27.1.3
+  languageName: unknown
+  linkType: soft
 
 "@standardnotes/utils@npm:^1.4.6, @standardnotes/utils@npm:^1.6.12":
   version: 1.6.12
@@ -2731,6 +2736,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/microtime@npm:^2.1.0":
+  version: 2.1.0
+  resolution: "@types/microtime@npm:2.1.0"
+  checksum: 6c23131fe46fd1b059c8d7e474a5ab60e703cf0f4a6ab0e3dbe36f1d394359fb4712dca696ff891b15482855465e6febc16acc56eaaf500864283d758b0c8dca
+  languageName: node
+  linkType: hard
+
 "@types/mime@npm:^1":
   version: 1.3.2
   resolution: "@types/mime@npm:1.3.2"