sinclairzx81 / typebox

Json Schema Type Builder with Static Type Resolution for TypeScript
Other
4.65k stars 150 forks source link

How to work with dates and timestamps #856

Closed Dhruv-Garg79 closed 3 months ago

Dhruv-Garg79 commented 3 months ago

Type.Date() is not accepting timestamp or ISO date.

Type.String({ format: 'date-time' }) results in below error

{
            "type": 49,
            "schema": {
                "format": "date-time",
                "type": "string"
            },
            "path": "/body/occurred_at",
            "value": "2024-04-30T08:54:33.666Z",
            "message": "Unknown format 'date-time'"
        }
sinclairzx81 commented 3 months ago

@Dhruv-Garg79 Hi,

Date handling can be a bit complex as applications need to encode, decode, validate and convert dates in various different ways. TypeBox provides the following functionality to handle them.

Register 'date-time' Format

"Unknown format 'date-time'"

TypeBox validators do not define any formats by default so you'll need to register them by way of the FormatRegistry. TypeBox includes some Ajv compatible formats in the example/formats if you're looking for format check implementations.

import { Type, FormatRegistry } from '@sinclair/typebox'
import { Value } from '@sinclair/typebox/value'

// Register the 'date-time' Format
import { IsDateTime } from './formats/index' // see examples/formats
FormatRegistry.Set('date-time', value => IsDateTime(value)) 

// ...

// Create String with Format
const IsoDate = Type.String({ format: 'date-time' })

// Check it 
const R = Value.Check(IsoDate, '2024-04-30T08:54:33.666Z') // true

Transform String to Date

Once you have the string format setup, you can implement additional logic to transform the string representation (which would be sent over the network, presumably via Json) into a JavaScript Date object.

import { Type, FormatRegistry } from '@sinclair/typebox'
import { Value } from '@sinclair/typebox/value'

// Register the 'date-time' Format
import { IsDateTime } from './formats/index' // see examples/formats
FormatRegistry.Set('date-time', value => IsDateTime(value)) 

// ...

// Create String with Format + Transform
const IsoDate = Type.Transform(Type.String({ format: 'date-time' }))
  .Decode(value => new Date(value))
  .Encode(value => value.toISOString())

// Check it 
const R = Value.Check(IsoDate, '2024-04-30T08:54:33.666Z') // true

// Decode it 
const D = Value.Decode(IsoDate, '2024-04-30T08:54:33.666Z') // Date(2024-04-30T08:54:33.666Z)

// Encode it 
const E = Value.Encode(IsoDate, D)                          // '2024-04-30T08:54:33.666Z'

The above is generally how you can approach Dates. It's usually good to abstract the validation details (be it calls to Check, Decode, Encode) into a module that registers the formats, and implements the value check and decode logic.

Hope this helps S

sinclairzx81 commented 3 months ago

@Dhruv-Garg79 Hiya,

Might close off this issue as it's more a general inquiry than an issue. However, If you run into any issues using the code examples above, feel free to ping on this thread.

All the best S