Skip to content

Commit

Permalink
chore(ui): Adjust weave0 timestamp resolver and documentation for par…
Browse files Browse the repository at this point in the history
…ity (#2628)

* docs: Add docstring for to_timestamp op to clarify the expected time unit

* chore: adjust implementation of weave0 timestamp resolver for parity with python backend
  • Loading branch information
domphan-wandb authored Oct 16, 2024
1 parent 320c836 commit fac9b9a
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 19 deletions.
40 changes: 39 additions & 1 deletion weave-js/src/core/ops/primitives/number.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
taggedValue,
} from '../../model';
import {testClient} from '../../testUtil';
import {opNumberFloor} from './number';
import {opNumberFloor, opNumberToTimestamp} from './number';

describe('number ops', () => {
describe('floor', () => {
Expand Down Expand Up @@ -88,4 +88,42 @@ describe('number ops', () => {
expect(await client.query(expr)).toEqual([1, null, 2]);
});
});

describe('timestamp', () => {
it('handles a unix timestamp in miliseconds', async () => {
const client = await testClient();
const expr = opNumberToTimestamp({val: constNumber(1729000000000)});
expect(await client.query(expr)).toEqual(1729000000000);
});

it('handles a unix timestamp in microseconds by converting to ms', async () => {
const client = await testClient();
const expr = opNumberToTimestamp({
val: constNumber(1729000000000 * 1000 * 1000),
});
expect(await client.query(expr)).toEqual(1729000000000);
});

it('handles a unix timestamp in nanoseconds by converting to ms', async () => {
const client = await testClient();
const expr = opNumberToTimestamp({
val: constNumber(1729000000000 * 1000 * 1000 * 1000),
});
expect(await client.query(expr)).toEqual(1729000000000);
});

it('handles negative numbers', async () => {
const client = await testClient();
const expr = opNumberToTimestamp({
val: constNumber(-1 * 1729000000000 * 1000 * 1000 * 1000),
});
expect(await client.query(expr)).toEqual(-1729000000000);
});

it('handles a unix timestamp in seconds by doing nothing', async () => {
const client = await testClient();
const expr = opNumberToTimestamp({val: constNumber(1729000000)});
expect(await client.query(expr)).toEqual(1729000000);
});
});
});
32 changes: 14 additions & 18 deletions weave-js/src/core/ops/primitives/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -655,37 +655,33 @@ export const opNumberCos = OpKinds.makeStandardOp({
resolver: ({n}) => Math.cos(n),
});

const timestampSecondUpperBound = 60 * 60 * 24 * 365 * 1000; // first 1000 years
const timestampMilliSecondUpperBound = timestampSecondUpperBound * 1000;
const timestampMicroSecondUpperBound = timestampMilliSecondUpperBound * 1000;
const timestampNanoSecondUpperBound = timestampMicroSecondUpperBound * 1000;
// Use min and max timestamps from python builtin datetime library
// for consistency between weave0 and weave_query resolver imeplemntation
const PY_DATETIME_MAX_MS = 50000000000000;
const PY_DATETIME_MIN_MS = -50000000000000;

// we will start by making this a simple millisecond converter, but
// in the future we can make the unit customizable.
export const opNumberToTimestamp = OpKinds.makeStandardOp({
name: 'number-toTimestamp',
argTypes: {val: 'number'},
description: `Converts a ${docType('number')} to a ${docType(
'timestamp'
)}. Values less than ${timestampSecondUpperBound} will be converted to seconds, values less than ${timestampMilliSecondUpperBound} will be converted to milliseconds, values less than ${timestampMicroSecondUpperBound} will be converted to microseconds, and values less than ${timestampNanoSecondUpperBound} will be converted to nanoseconds.`,
argDescriptions: {val: 'Number to convert to a timestamp'},
description: `Converts a ${docType('number')} to a ${docType('timestamp')}.`,
argDescriptions: {
val: 'Number (unix time in miliseconds, microseconds, or nanoseconds) to convert to a timestamp',
},
returnValueDescription: `Timestamp`,
returnType: inputTypes => ({
type: 'timestamp',
unit: 'ms',
}),
resolver: ({val}) => {
if (val < timestampSecondUpperBound) {
return Math.floor(val * 1000);
} else if (val < timestampMilliSecondUpperBound) {
return Math.floor(val);
} else if (val < timestampMicroSecondUpperBound) {
return Math.floor(val / 1000);
} else if (val < timestampNanoSecondUpperBound) {
return Math.floor(val / 1000 / 1000);
} else {
return null;
while (
Math.abs(val) > PY_DATETIME_MAX_MS ||
Math.abs(val) < PY_DATETIME_MIN_MS
) {
val = val / 1000;
}
return val;
},
});

Expand Down

0 comments on commit fac9b9a

Please sign in to comment.