MCPcopy
hub / github.com/spencermountain/spacetime

github.com/spencermountain/spacetime @7.13.0 sqlite

repository ↗ · DeepWiki ↗ · release 7.13.0 ↗
1,403 symbols 4,137 edges 279 files 39 documented · 3%
README
<img width="277" alt="spacetime logo" src="https://user-images.githubusercontent.com/399657/31140478-80a4269a-a842-11e7-8dbf-b541fe3e87a7.png">

Isn't it weird how we can do math in our head, but not date math?

- how many days until the end of the year?

-what time was it, 11 hours ago?

-is it lunchtime in france?

and worse - there is no real date calculator.

people end up asking google, and going to weird websites.

that's bad.

spacetime is a date-calculator,

It's very small, and very handy.

let s = spacetime.now()

s.diff(s.endOf('year'), 'days')
// 292

s.subtract(11, 'hours').time()
// 6:50am

s = s.goto('Europe/Paris')
s.isAfter(s.time('11:00am'))
// true 🥐

  • calculate time in remote timezones
  • support daylight savings, leap years, and hemispheres
  • Moment-like API (but immutable)
  • Orient time by quarter, season, month, week..
  • Zero Dependencies - (no Intl API)
  • weighs about 40kb.
  • has a cool plugin thing.
  • frequent updates for approaching DST changes
  • support for upcoming Temporal standards

<script src="https://unpkg.com/spacetime"></script>
<script>
  var d = spacetime('March 1 2012', 'America/New_York')
  //set the time
  d = d.time('4:20pm')

  d = d.goto('America/Los_Angeles')
  d.time()
  //'1:20pm'
</script>

npm install spacetime

const spacetime = require('spacetime')
let d = spacetime.now('Europe/Paris')
d.dayName()
//'Wednesday'
d.isAsleep()
//true

typescript / babel / deno:

import spacetime from 'spacetime'
let d = spacetime.now()
d.format('nice')
//'Apr 1st, 4:32pm'

ts docs

AGENTS.md LLM docs

Demo     •     Full API

<img width="550" src="https://user-images.githubusercontent.com/399657/50862221-1d904a00-1369-11e9-891c-5f4e9fbb9ec0.gif" />

plugins:

<a href="https://github.com/spencermountain/spacetime/tree/master/plugins/geo">spacetime-geo</a>
• <a href="https://github.com/spencermountain/spacetime/tree/master/plugins/daylight">spacetime-daylight</a>
• <a href="https://github.com/spencermountain/spacetime/tree/master/plugins/age">spacetime-age</a>






<a href="https://github.com/spencermountain/scal">spacetime-calendar</a>
• <a href="https://github.com/spencermountain/spacetime/tree/master/plugins/week-of-month">week-of-month</a>
• <a href="https://github.com/spencermountain/spacetime/tree/master/plugins/week-start">week-start</a>

Date Inputs:

we can parse all the normal stuff, and some fancy stuff:

//epoch
s = spacetime(1489520157124)

//array [yyyy, m, d] (zero-based months, 1-based days)
s = spacetime([2017, 5, 2])

//iso
s = spacetime('July 2, 2017 5:01:00')

// All inputs accept a timezone, as 2nd param:
s = spacetime(1489520157124, 'Canada/Pacific')
s = spacetime('2019/05/15', 'Canada/Pacific')

// or set the offset right in the date-string (ISO-8601)
s = spacetime('2017-04-03T08:00:00-0700')
// 'Etc/GMT-7'

// Some helpers
s = spacetime.now()
s = spacetime.today() // This morning
s = spacetime.tomorrow() // Tomorrow morning
s = spacetime.min() // the earliest-possible date (271,821 bc)
s = spacetime.max() // the furthest-possible future date (27k years from now)

// To get the native Date object back
// (this bails back to the local timezone)
jsDate = spacetimeDate.toNativeDate()

for fancier natural-language inputs, use compromise-dates.

Get & Set dates:

you can whip things around, but stay intuitive

s.date() // 14
s.year() // 2017
s.season() // Spring
s = s.hour(5) // Change to 5am
s = s.date(15) // Change to the 15th

s = s.day('monday') // Change to (this week's) monday
s = s.day('monday', true) // go forward to monday
s = s.day('monday', false) // go backward to monday

s = s.month('march') // Change to (this year's) March 1st
s = s.quarter(2) // Change to April 1st
s.era() // 'BC'/'AD'
s.decade() // 2000
s.century() // 21

// Percentage-based information
s.progress().month // 0.23 - we're a quarter way through the month
s.progress().day // 0.48 - almost noon
s.progress().hour // 0.99 - 59 minutes and 59 seconds

// Add/subtract methods
s = s.add(1, 'week')
s = s.add(3, 'quarters')
s = s.subtract(2, 'months').add(1, 'day')

// start-of/end-of
s = s.startOf('day') // 12:00am
s = s.startOf('month') // 12:00am, April 1st
s = s.endOf('quarter') // 11:59:59pm, June 30th

s = s.nearest('hour') //round up/down to the hour
s = s.nearest('quarter-hour') //5:15, 5:30, 5:45..
s = s.next('month') //start of the next month
s = s.last('year') //start of the last year

// fill-in all dates between a range
s.every('week', 'Jan 1st 2020') // (in tz of starting-date)

//utilities:
s.clone() // Make a copy
s.isValid() // Sept 32nd → false
s.isAwake() // it's between 8am → 10pm
s.json() // get values in every unit as key-val object

if it's 9am on tuesday, and you add a week, it will still be 9am on tuesday. ... even if some crazy changes happen.

setter methods also support a handy 2nd param that controls whether it should be set forward, or backward.

s = s.time('4:00pm') // 4pm today
s = s.time('4:00pm', true) // the next 4pm in the future
s = s.time('4:00pm', false) // the most-recent 4pm

s = s.set('march 5th 2020')
s = s.set('march 4th') // 2020 (same year)
s = s.set('march 4th', true) // 2021
s = s.set('march 6th', false) // 2019

it's actually a little surprising how helpful this is.

Comparisons:

let s = spacetime([2017, 5, 2])
let start = s.subtract(1, 'milliseconds')
let end = s.add(1, 'milliseconds')

// gt/lt/equals
s.isAfter(d) // True
s.isEqual(d) // False
s.isBefore(d) // False
s.isBetween(start, end, inclusive?) // True

// Comparison by unit
s.isSame(d, 'year') // True
s.isSame(d, 'date') // False
s.diff(d, 'day') // 5
s.diff(d, 'month') // 0

//make a human-readable diff
let before = spacetime([2018, 3, 28])
let now = spacetime([2017, 3, 28]) //one year later
now.since(before)
// {diff: { months: 11, days: 30, ...},  rounded: 'in 12 months'  }

all comparisons are done with sensitivity of timezone - 8am EST is < 8am PST.

Timezones:

the best way to describe a timezone is an IANA code:

// Roll into a new timezone, at the same moment
s = s.goto('Australia/Brisbane')

if you want to support relaxed timezone names like 'EST', Eastern time, use timezone-soft

spacetime.extend(require('timezone-soft'))

s = s.goto('milwaukee') // 'America/Chicago'
s = s.goto('-7h') // UTC-7
s = s.goto('GMT+8') // -8h!
// (these should be used with some caution)

play-around with timezones, and their DST-changes:

//list timezones by their current time
spacetime.whereIts('8:30pm', '9:30pm') // ['America/Winnipeg', 'America/Yellowknife'... ]
spacetime.whereIts('9am') //(within this hour)

// Timezone metadata
s.timezone().name // 'Canada/Eastern' (either inferred or explicit)
s.hemisphere() // North
s.timezone().current.offset // -4 (in hours)
s.hasDST() // True
s.isDST() // True

//list all timezones
spacetime.timezones()

you can flip-around the world pretty quick.

spacetime will use your local timezone, by default:

.goto(null) will pluck your current tz safely from your browser or computer.

spacetime().time('4:30pm').goto('Europe/Paris').goto(null).time()
// 4:30pm

If, for some reason, you want to change the timezone without changing the date, you can do this via the .timezone(str) setter:

let s = spacetime('2023-01-01T5:30[America/Denver]')
s = s.timezone('Europe/Zagreb') // hot-swap
console.log(s.isoFull())
// '2023-01-01T05:30:00.000+01:00[Europe/Zagreb]' (same time, new tz)

Date Formatting:

it's a pretty-sensible process to create nice-looking dates:

// Date + time formatting
s.format('time') // '5:01am'
s.format('numeric-uk') // 02/03/2017
s.format('month') // 'April'
s.format('month-short') // 'Apr'
s.format('month-pad') // '03'
s.format('iso-month') // '04'

//if you want more complex formats, use {}'s
s.format('{year}-{date-pad}-{month-pad}') // '2018-02-02'
s.format("{hour} o'clock") // '2 o'clock'
s.format('{time}{ampm} sharp') // '2:30pm sharp'

//if you prefer, you can also use unix-formatting
s.unixFmt('yyyy.MM.dd h:mm a') // '2017.Nov.16 11:34 AM'

// support for the new Temporal ISO format
s.format('iso-full') // '2011-12-03T10:15:30.010+01:00[Europe/Paris]'

// support for the SQL ISO 9075 format
s.format('sql') // '2011-12-03 10:15:30'

Limitations & caveats

◆ Historical timezone info

DST changes move around all the time, and timezones pop-in and out of existence. We store and use only the latest DST information, and apply it to historical dates.

◆ International date line

.goto() never crosses the date-line. This is mostly the intuitive behaviour.

But if you're in Fiji (just west of the date line), and you go to Midway (just east of the date line), .goto() will subtract a bunch of hours, instead of just adding one.

◆ Destructive changes

if it's 2:30pm and you add a month, it should still be 2:30pm. Some changes are more destructive than others. Many of thse choices are subjective, but also sensible.

◆ 0-based vs 1-based ...

for better or worse we copy the JavaScript spec for 0-based months, and 1-based dates.

Extension points exported contracts — how you extend this code

SpacetimeUtils (Interface)
(no doc) [2 implementers]
plugins/week-start/types/types.d.ts
I18nOptions (Interface)
(no doc)
types/constraints.d.ts
Spacetime (Interface)
(no doc)
types/types.d.ts
SpacetimeConstructorOptions (Interface)
(no doc)
types/constructors.d.ts
SpacetimeMain (Interface)
(no doc)
plugins/week-start/types/types.d.ts
TimezoneMeta (Interface)
(no doc)
types/types.d.ts
SpacetimeConstructor (Interface)
(no doc)
types/constructors.d.ts
SpacetimeGetterSetters (Interface)
(no doc)
plugins/week-start/types/types.d.ts

Core symbols most depended-on inside this repo

year
called by 680
types/types.d.ts
format
called by 547
plugins/ticks/assets/bundle.js
date
called by 533
types/types.d.ts
month
called by 459
types/types.d.ts
hour
called by 289
types/types.d.ts
timezone
called by 277
types/types.d.ts
minute
called by 257
types/types.d.ts
time
called by 250
types/types.d.ts

Shape

Function 1,139
Method 204
Class 42
Interface 18

Languages

TypeScript100%

Modules by API surface

plugins/ticks/assets/bundle.js407 symbols
builds/spacetime.cjs122 symbols
builds/spacetime.mjs63 symbols
builds/spacetime.min.js63 symbols
plugins/ticks/builds/spacetime-ticks.mjs62 symbols
plugins/ticks/builds/spacetime-ticks.cjs62 symbols
plugins/week-start/builds/spacetime-week-start.min.js61 symbols
plugins/week-start/builds/spacetime-week-start.mjs60 symbols
plugins/week-start/builds/spacetime-week-start.cjs60 symbols
plugins/ticks/builds/spacetime-ticks.min.js60 symbols
types/types.d.ts43 symbols
plugins/daylight/builds/spacetime-daylight.mjs28 symbols

Dependencies from manifests, versioned

@rollup/plugin-commonjs29.0.2 · 1×
@rollup/plugin-json6.1.0 · 1×
@rollup/plugin-node-resolve16.0.3 · 1×
@rollup/plugin-terser1.0.0 · 1×
eslint-plugin-regexp3.1.0 · 1×
minimist1.2.5 · 1×
rollup4.62.2 · 1×
shelljs0.10.0 · 1×
spacetime>=7.4.0 · 1×
spacetime-geo1.4.1 · 1×
spencer-color0.1.0 · 1×
spencer-css1.1.3 · 1×

For agents

$ claude mcp add spacetime \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact