All Projects → spencermountain → Spacetime

spencermountain / Spacetime

Licence: other
A lightweight javascript timezone library

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Spacetime

Friend-Time
Discord bot - Friend Time helps your server coordinate times and events by converting times mentioned in chat between time zones!
Stars: ✭ 62 (-98.21%)
Mutual labels:  timezone, timezones, timezone-conversion
dayjs
Extended fork of Day.js - 2KB immutable date library alternative to Moment.js
Stars: ✭ 36 (-98.96%)
Mutual labels:  date-formatting, timezones
Swiftdate
🐔 Toolkit to parse, validate, manipulate, compare and display dates, time & timezones in Swift.
Stars: ✭ 6,661 (+92.35%)
Mutual labels:  timezone, date-formatting
ng2-timezone-selector
A simple Angular module to create a timezone selector using moment-timezone.
Stars: ✭ 12 (-99.65%)
Mutual labels:  timezone, timezones
Time
Building a better date/time library for Swift
Stars: ✭ 1,983 (-42.74%)
Mutual labels:  timezone, date-formatting
Shell-Scripts
Shell scripts about some basic topics, current time, calculator, sorting, restaurant and more.
Stars: ✭ 100 (-97.11%)
Mutual labels:  timezone
django-timezone-field
A Django app providing DB, form, and REST framework fields for zoneinfo and pytz timezone objects.
Stars: ✭ 322 (-90.7%)
Mutual labels:  timezones
timezones
Nim timezone library compatible with the standard library.
Stars: ✭ 37 (-98.93%)
Mutual labels:  timezone
intl-format
A wrapper library for PHP to format and internationalize values in messages like sprintf
Stars: ✭ 12 (-99.65%)
Mutual labels:  timezone
node-red-contrib-moment
Node-Red Node that produces formatted Date/Time output using the Moment.JS library. Timezone, dst and locale aware.
Stars: ✭ 31 (-99.1%)
Mutual labels:  timezone
setup-timezone
setup timezone for actions
Stars: ✭ 20 (-99.42%)
Mutual labels:  timezone
next-intl
A minimal, but complete solution for internationalization in Next.js apps. 🌐
Stars: ✭ 242 (-93.01%)
Mutual labels:  date-formatting
vue-date-fns
Date filter for Vue based on the date-fns.
Stars: ✭ 21 (-99.39%)
Mutual labels:  date-formatting
TimeZoneLocate
Time zone for locations offline in Swift (iOS).
Stars: ✭ 30 (-99.13%)
Mutual labels:  timezone
gwt-time
Backport of functionality based on JSR-310 to GWT. This is NOT an implementation of JSR-310.
Stars: ✭ 17 (-99.51%)
Mutual labels:  timezone
slack-timezone-bot
🤖⏰ Slack bot to show time in users' timezones
Stars: ✭ 51 (-98.53%)
Mutual labels:  timezone
nepali-datetime
Python's core datetime inspired nepali datetime (BS date & NPT) package 🇳🇵
Stars: ✭ 36 (-98.96%)
Mutual labels:  timezone
Daylight-Calendar-ICS
Daylight Calendar is a dynamically generated .ics calendar that you can host and subscribe to in Google Calendar, iCal, or other calendar software.
Stars: ✭ 22 (-99.36%)
Mutual labels:  daylight-savings
google-photos-timezone-fix
Iterates over photos in given Google Photos album and edits date/time/timezone of each photo in order to fix their order
Stars: ✭ 22 (-99.36%)
Mutual labels:  timezone
NTP
NTP library for Arduino framework
Stars: ✭ 20 (-99.42%)
Mutual labels:  timezone

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.minus(11, 'hours').time()
// 6:50am

s = s.now('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.

<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'

Demo     •     Full API

plugins:

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
// NOTE: this returns the date in the local browsers 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

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'

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.

ISO-formatting is different, so keep on your toes.

see more considerations and gotchas

Daylight-savings gotchas

We've written in detail about how spacetime handles Daylight-savings changes here

Fall DST changes have an hour that is repeated twice. There are a lot of tricky situations that come from this. Add 10 minutes at 1:55am, and a spacetime diff may show -50mins. Within an hour of this change, some spacetime methods may be off-by-one hour.

Springtime DST changes are generally smoother than Fall ones.

Config:

Ambiguity warnings:

javascript dates use millisecond-epochs, instead of second-epochs, like some other languages. This is a common bug, and spacetime can warn if you set an epoch within January 1970. to enable:

let s = spacetime(123456, 'UTC', {
  silent: false
})
s.log() // "Jan 1st, 12:02am"

There is another situation where you may see a console.warn - if you give it a timezone, but then set a ISO-date string with a different offset, like 2017-04-03T08:00:00-0700 (-7hrs UTC offset). It sets the timezone to UTC-7, but also gives a warning.

let s = spacetime('2017-04-03T08:00:00-0700', 'Canada/Eastern', {
  silent: false
})
s.timezone().name // "Etc/GMT-7"

Configure 'today' context:

spacetime makes some assumptions about some string inputs:

// assumes start of month
let s = spacetime('June 1992')
s.date() // 1

// assumes current year
let s = spacetime('June 5th')
s.year() // 2020 (or whatever it is now)

// assumes Jan 1st
let s = spacetime('2030')
s.month() // 'January'

you can configure this assumed date (usually for testing) by passing it in as an option:

let today = {
  month: 3,
  date: 4,
  year: 1996
}
let s = spacetime('June 5th', null, { today: today })
s.year() // 1996

it also works for spacetime.now(tz, {today:today}) and others.

Extending/Plugins:

you can throw any methods onto the Spacetime class you want, with spacetime.extend():

spacetime.extend({
  isHappyHour: function () {
    return this.hour() === 16
  }
})

let s = spacetime.now('Australia/Adelaide')
s.isHappyHour()
//false

s = s.time('4:30pm')
s.isHappyHour()
//true

DD/MM/YYY interpretation:

by default spacetime uses the American interpretation of ambiguous date formats, like javascript does:

spacetime('12/01/2018') //dec 1st

// unless it's clear (>12):
spacetime('13/01/2018') //jan 13th

you can change this behaviour by passing in a dmy option, like this:

spacetime('12/01/2018', null, { dmy: true }) //jan 12th

this format is more common in britain, and south america.

Custom languages:

a.i18n({
  days: {
    long: ['domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado'],
    short: ['dom', 'lun', 'mar', 'mié', 'jue', 'vie', 'sáb']
  },
  months: {
    long: [...],
    short: ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic'],
  },
  useTitleCase: true // automatically in .format()
});
a.format('day') //'Sábado'

Configure start of week:

by default, the start of the week is monday.

You can determine the week by the official country setting, with spacetime-week

let s = spacetime.now()
s = s.weekStart('sunday')

s = s.startOf('week')
s.dayName()
//sunday

s = s.endOf('week')
s.dayName()
//saturday

See also:

thank you to the amazing timeanddate.com

Apache 2.0

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].