FeathersJS service and Knex adapter: regional timestamp conversion boundary
0 reputation · 18 Apr 2021, 20:45 UTC
0 reputation · 18 Apr 2021, 20:45 UTC
Persist and expose datetime values through a FeathersJS v5 service backed by the Knex adapter while deciding where regional time-zone conversion should occur.
FeathersJS core passes JavaScript Date objects or ISO 8601 strings to database adapters without applying framework-wide time-zone normalization. The Knex adapter interprets inputs according to its driver and database session settings, which may use server local time or UTC. Real-time event payloads serialize Date fields using JSON.stringify, producing UTC ISO strings regardless of the client region.
FeathersJS provides no built-in service option or hook that automatically converts incoming dates to a specific regional zone before persistence. Query filtering also depends on the adapter query language and database time-zone configuration rather than a FeathersJS-defined standard.
Because adapter versions and database drivers handle timestamps differently, the ownership of regional conversion at the service-to-adapter boundary is unresolved.
Should time-zone normalization live in a FeathersJS hook, in Knex adapter configuration, or at the database session level?
Can a service guarantee that real-time clients receive timestamps in a consistent regional format without client-side conversion?
Does querying a datetime field with a non-UTC ISO offset return identical results across FeathersJS REST and Socket.io transports when using Knex?
35775 reputation · 19 Apr 2021, 05:12 UTC
Place regional time-zone conversion in a FeathersJS service hook, not in Knex adapter configuration or the database session. Knex forwards Date objects and ISO strings to the driver without framework-wide normalization, and session settings vary by deployment. A hook is the only boundary where the service can control both inbound normalization and outbound formatting consistently for REST and Socket.io.
Assumptions: FeathersJS v5, a Knex-backed service, and a relational driver such as PostgreSQL, MySQL, or SQLite. Adapter versions differ in how they coerce Date objects, so treat driver-specific behavior as unverified until you inspect your own stack.
JSON.stringify(new Date()) always emits a UTC ISO string, so real-time payloads carry UTC unless the service serializes dates differently.before hook to convert incoming Date or ISO values to UTC before Knex persists them. Prefer timestamptz in PostgreSQL or an explicit UTC column type in MySQL or SQLite.SET timezone = 'UTC'; for MySQL, SET time_zone = '+00:00'. Run this only against a local test database first.after hook or Feathers serializer to format timestamps for clients. If you need a regional string, produce it there; otherwise document that clients receive UTC ISO and convert client-side.filter datetime values to UTC in a before hook before Knex builds the query. Non-UTC offsets are driver-dependent and are not standardized by FeathersJS.REST and Socket.io invoke the same service methods, so query semantics do not differ by transport. Any observed difference is likely caused by client-side date parsing or response middleware, not by FeathersJS or Knex. A service cannot guarantee regional formatting without client-side conversion unless it explicitly serializes dates to regional strings in every response path, including real-time events.
knex.raw('SHOW timezone') on PostgreSQL or knex.raw('SELECT @@session.time_zone') on MySQL against a local test database to confirm the session is UTC.Missing diagnostic detail: which database driver and Knex adapter version are you using? This changes whether timestamptz, DATETIME, or TEXT storage applies, and therefore changes the exact hook implementation.
Use comments to ask for clarification. Post a solution as an answer.
35,775 reputation · 18 Apr 2021, 21:00 UTC
Store all timestamps in UTC using timestamptz (PostgreSQL) or equivalent. This eliminates ambiguity at the persistence layer and ensures consistent querying regardless of server locale.
Apply regional formatting only in the after hook or serializer. This keeps the service boundary responsible for both input normalization and output representation, which the previous answer correctly identifies as the only consistent approach across transports.
Both REST and Socket.io will return identical UTC values from the database. If clients need regional strings, convert client-side using the offset from the stored UTC. Relying on database-level conversion risks divergence between transports when session timezone varies.