Skip to content

Instantly share code, notes, and snippets.

@pithu
Last active June 2, 2016 07:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pithu/23128485d022af27a5b36b3fbbf6d92e to your computer and use it in GitHub Desktop.
Save pithu/23128485d022af27a5b36b3fbbf6d92e to your computer and use it in GitHub Desktop.
Implement a threeten ZoneRegion by a MomentZoneRules wrapper
import {LocalDate, DayOfWeek, TemporalAdjusters, Instant, ZoneId, ZoneOffset, ZonedDateTime, LocalTime} from 'js-joda'
import {tz} from 'moment-timezone'
class MomentZoneRules {
constructor(tz) {
this.untils = tz.untils;
// localUntils is an array taken from original utc untils, modified by the reverse of the maximum (of actual, previous) offset
// thus, if you take the epochMillis of a LocalDateTime interpreted at UTC and binsearch it here,
// you should find the index of the transition, that is either unique or is before the transition in case of gap/overlap
this.localUntils = tz.untils.map((v, i) => v - Math.min(tz.offsets[i], tz.offsets[Math.max(0, i - 1)]) * 60000);
this.offsets = tz.offsets.map((v) => ZoneOffset.ofTotalMinutes(-v));
}
isFixedOffset() {
return false;
}
offset(instantOrLocalDateTime) {
if (instantOrLocalDateTime instanceof Instant) {
return this.offsetOfInstant(instantOrLocalDateTime);
} else {
return this.offsetOfLocalDateTime(instantOrLocalDateTime);
}
}
offsetOfInstant(instant) {
return this._offset(this.untils, instant.toEpochMilli());
}
offsetOfLocalDateTime(localDateTime){
let localMillis = Instant.from(ZonedDateTime.of(localDateTime, ZoneId.UTC)).toEpochMilli();
return this._offset(this.localUntils, localMillis);
}
_offset(array, timestamp) {
let nextIndex = search(array, timestamp);
if (nextIndex < 0) nextIndex = this.offsets.length - 1;
return this.offsets[nextIndex]
}
}
class ZoneRegion extends ZoneId {
constructor(id, rules) {
super();
this._id = id;
this._rules = rules;
}
rules() {
return this._rules;
}
}
class MomentZoneId extends ZoneRegion {
constructor(id) {
super(id, new MomentZoneRules(tz.zone(id)));
}
}
const TZ = new MomentZoneId('Europe/Berlin');
// modified bin-search, to always find existing indices for non-empty arrays
// value in array at index is larger than input value (or last index of array)
function search(array, value) {
let hi = array.length - 1, lo = -1, mid;
while (hi - lo > 1) {
if (array[mid = hi + lo >> 1] <= value) {
lo = mid;
} else {
hi = mid;
}
}
return hi;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment