Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

basic wasm support #331

Merged
merged 11 commits into from Aug 23, 2019
5 changes: 5 additions & 0 deletions .travis.yml
Expand Up @@ -21,6 +21,11 @@ env:
global:
- LD_LIBRARY_PATH: /usr/local/lib
- CLIPPY: n
install:
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then source $HOME/.nvm/nvm.sh; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then nvm install 10; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then nvm use 10; fi
- if [ "$TRAVIS_RUST_VERSION" != "1.13.0" ]; then curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh; fi
script: ./ci/travis.sh
notifications:
email: false
Expand Down
8 changes: 8 additions & 0 deletions Cargo.toml
Expand Up @@ -35,13 +35,21 @@ num-traits = { version = "0.2", default-features = false }
rustc-serialize = { version = "0.3.20", optional = true }
serde = { version = "1", optional = true }


[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies]
wasm-bindgen = { version = "0.2" }
js-sys = "0.3" # contains FFI bindings for the JS Date API

[dev-dependencies]
serde_json = { version = "1" }
serde_derive = { version = "1" }
bincode = { version = "0.8.0" }
num-iter = { version = "0.1.35", default-features = false }
doc-comment = "0.3"

[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dev-dependencies]
wasm-bindgen-test = "0.2"

[package.metadata.docs.rs]
all-features = true

Expand Down
13 changes: 13 additions & 0 deletions ci/travis.sh
Expand Up @@ -48,6 +48,18 @@ build_and_test() {
channel build -v --no-default-features --features serde,rustc-serialize
TZ=Asia/Katmandu channel test -v --no-default-features --features serde,rustc-serialize --lib

if [ -n "${TRAVIS}" ] && [ "${TRAVIS_RUST_VERSION}" != "1.13.0" ]; then
# wasm tests
touch tests/wasm.rs # ensure rebuild happens so TZ / NOW take effect
TZ=ACST-9:30 NOW=$(date +%s) wasm-pack test --node
touch tests/wasm.rs
TZ=EST4 NOW=$(date +%s) wasm-pack test --node
touch tests/wasm.rs
TZ=UTC0 NOW=$(date +%s) wasm-pack test --node
touch tests/wasm.rs
TZ=Asia/Katmandu NOW=$(date +%s) wasm-pack test --node
fi

if [[ "$CHANNEL" == stable ]]; then
if [[ -n "$TRAVIS" ]] ; then
check_readme
Expand Down Expand Up @@ -82,6 +94,7 @@ check_readme() {

rustc --version
cargo --version
node --version

CHANNEL=nightly
if [ "x${CLIPPY}" = xy ] ; then
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Expand Up @@ -414,6 +414,10 @@ extern crate serde as serdelib;
#[cfg(test)]
#[macro_use]
extern crate doc_comment;
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
extern crate wasm_bindgen;
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
extern crate js_sys;

#[cfg(test)]
doctest!("../README.md");
Expand Down
13 changes: 12 additions & 1 deletion src/offset/local.rs
Expand Up @@ -87,9 +87,21 @@ impl Local {
}

/// Returns a `DateTime` which corresponds to the current date.
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
pub fn now() -> DateTime<Local> {
tm_to_datetime(oldtime::now())
}

/// Returns a `DateTime` which corresponds to the current date.
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub fn now() -> DateTime<Local> {
use super::Utc;
let now: DateTime<Utc> = super::Utc::now();

// Workaround missing timezone logic in `time` crate
let offset = FixedOffset::west((js_sys::Date::new_0().get_timezone_offset() as i32) * 60);
DateTime::from_utc(now.naive_utc(), offset)
}
}

impl TimeZone for Local {
Expand Down Expand Up @@ -179,4 +191,3 @@ mod tests {
"unexpected timestr {:?}", timestr);
}
}

15 changes: 13 additions & 2 deletions src/offset/utc.rs
Expand Up @@ -4,7 +4,7 @@
//! The UTC (Coordinated Universal Time) time zone.

use std::fmt;
#[cfg(feature="clock")]
#[cfg(all(feature="clock", not(all(target_arch = "wasm32", not(target_os = "emscripten")))))]
use oldtime;

use naive::{NaiveDate, NaiveDateTime};
Expand Down Expand Up @@ -38,11 +38,23 @@ impl Utc {
pub fn today() -> Date<Utc> { Utc::now().date() }

/// Returns a `DateTime` which corresponds to the current date.
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
pub fn now() -> DateTime<Utc> {
let spec = oldtime::get_time();
let naive = NaiveDateTime::from_timestamp(spec.sec, spec.nsec as u32);
DateTime::from_utc(naive, Utc)
}

/// Returns a `DateTime` which corresponds to the current date.
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub fn now() -> DateTime<Utc> {
let now = js_sys::Date::new_0();
let millisecs_since_unix_epoch: u64 = now.get_time() as u64;
let secs = millisecs_since_unix_epoch / 1000;
let nanos = 1_000_000 * (millisecs_since_unix_epoch - 1000 * secs);
let naive = NaiveDateTime::from_timestamp(secs as i64, nanos as u32);
DateTime::from_utc(naive, Utc)
}
}

impl TimeZone for Utc {
Expand Down Expand Up @@ -72,4 +84,3 @@ impl fmt::Debug for Utc {
impl fmt::Display for Utc {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "UTC") }
}

30 changes: 30 additions & 0 deletions tests/wasm.rs
@@ -0,0 +1,30 @@
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
mod test {
extern crate chrono;
extern crate wasm_bindgen_test;

use self::chrono::prelude::*;
use self::wasm_bindgen_test::*;

use std::env;

#[wasm_bindgen_test]
fn now() {
let utc: DateTime<Utc> = Utc::now();
let local: DateTime<Local> = Local::now();

// Ensure time fetched is correct
let actual = Utc.datetime_from_str(env!("NOW"), "%s").unwrap();
assert!(utc - actual < chrono::Duration::minutes(5));

// Ensure offset retrieved when getting local time is correct
let expected_offset = match env!("TZ") {
"ACST-9:30" => FixedOffset::east(19 * 30 * 60),
"Asia/Katmandu" => FixedOffset::east(23 * 15 * 60), // No DST thankfully
"EST4" => FixedOffset::east(-4 * 60 * 60),
"UTC0" => FixedOffset::east(0),
_ => panic!("unexpected TZ"),
};
assert_eq!(&expected_offset, local.offset());
}
}