diff --git a/.travis.yml b/.travis.yml index d74f3425e8..ca0e2d01c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/Cargo.toml b/Cargo.toml index cf2da027c5..4e246f08fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,11 @@ 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" } @@ -42,6 +47,9 @@ 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 diff --git a/ci/travis.sh b/ci/travis.sh index 4a974b1398..2747fee764 100755 --- a/ci/travis.sh +++ b/ci/travis.sh @@ -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 @@ -82,6 +94,7 @@ check_readme() { rustc --version cargo --version +node --version CHANNEL=nightly if [ "x${CLIPPY}" = xy ] ; then diff --git a/src/lib.rs b/src/lib.rs index 0df5cdd518..2962e65ae6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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"); diff --git a/src/offset/local.rs b/src/offset/local.rs index 6aa4ab7558..68c27c40c2 100644 --- a/src/offset/local.rs +++ b/src/offset/local.rs @@ -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 { 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 { + use super::Utc; + let now: DateTime = 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 { @@ -179,4 +191,3 @@ mod tests { "unexpected timestr {:?}", timestr); } } - diff --git a/src/offset/utc.rs b/src/offset/utc.rs index d4e8d10b5a..36f4e5fe60 100644 --- a/src/offset/utc.rs +++ b/src/offset/utc.rs @@ -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}; @@ -38,11 +38,23 @@ impl Utc { pub fn today() -> Date { 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 { 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 { + 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 { @@ -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") } } - diff --git a/tests/wasm.rs b/tests/wasm.rs new file mode 100644 index 0000000000..b95d9f0b02 --- /dev/null +++ b/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::now(); + let local: DateTime = 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()); + } +}