Skip to content

Commit e8f6e50

Browse files
committed
Getting closer to local date time offset rules
Fixed offset, but still failling in gap and overlap situations
1 parent c231538 commit e8f6e50

File tree

2 files changed

+126
-6
lines changed

2 files changed

+126
-6
lines changed

src/MomentZoneRules.js

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export class MomentZoneRules extends ZoneRules{
5151
*/
5252
offsetOfEpochMilli(epochMilli){
5353
let index = binarySearch(this._tzdbInfo.untils, epochMilli);
54-
return ZoneOffset.ofTotalSeconds(roundDown(this._tzdbInfo.offsets[index]*-60));
54+
return ZoneOffset.ofTotalSeconds(-this._offsetByIndexInSeconds(index));
5555
}
5656

5757

@@ -84,10 +84,35 @@ export class MomentZoneRules extends ZoneRules{
8484
* @return {ZoneOffset} the best available offset for the local date-time, not null
8585
*/
8686
offsetOfLocalDateTime(localDateTime){
87-
// FIXME this is wrong, just a quick cut through.
88-
// It's just working with about one day distance to the next dst
89-
let epochMilli = localDateTime.toEpochSecond(ZoneId.UTC) * 1000;
90-
return this.offsetOfEpochMilli(epochMilli);
87+
// FIXME work in progress
88+
const utcEpochMilli = localDateTime.toEpochSecond(ZoneId.UTC) * 1000;
89+
const index = binarySearch(this._tzdbInfo.untils, utcEpochMilli);
90+
let offsetSec = this._offsetByIndexInSeconds(index);
91+
const epochMilli = utcEpochMilli + offsetSec * 1000;
92+
93+
const nextIndex = this._clipIndex(index + 1);
94+
const nextEpochMilliDst = this._tzdbInfo.untils[index];
95+
const prevIndex = this._clipIndex(index - 1);
96+
const prevEpochMilliDst = this._tzdbInfo.untils[prevIndex];
97+
if(epochMilli > nextEpochMilliDst) {
98+
offsetSec = this._offsetByIndexInSeconds(nextIndex);
99+
} else if (epochMilli < prevEpochMilliDst) {
100+
offsetSec = this._offsetByIndexInSeconds(prevIndex);
101+
}
102+
return ZoneOffset.ofTotalSeconds(-offsetSec);
103+
}
104+
105+
_clipIndex(index) {
106+
if (index < 0) {
107+
return 0;
108+
} else if (index >= this._tzdbInfo.offsets.length) {
109+
return this._tzdbInfo.offsets.length - 1;
110+
} else {
111+
return index;
112+
}
113+
}
114+
_offsetByIndexInSeconds(index){
115+
return roundDown(+this._tzdbInfo.offsets[index]*60);
91116
}
92117

93118
/**

test/MomentZoneRulesTest.js

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
Instant, LocalDateTime, ZonedDateTime, ZoneId, ZoneOffset
1111
} from 'js-joda';
1212

13-
import { assertEquals } from './testUtils';
13+
import { assertEquals, dataProviderTest } from './testUtils';
1414
import './useMomentZoneRules';
1515

1616
import { MomentZoneRulesProvider } from '../src/MomentZoneRulesProvider';
@@ -137,6 +137,101 @@ describe('MomentZoneRules', () => {
137137

138138
});
139139

140+
describe('ofLocal', () => {
141+
const LOCAL_DATE_IN_SUMMER = LocalDateTime.of(2016, 6, 30, 11, 30, 59, 500);
142+
const LOCAL_DATE_IN_WINTER = LocalDateTime.of(2016, 12, 21, 11, 30, 59, 500);
143+
144+
const FIXED_ZONE_06 = ZoneOffset.ofHours(6);
145+
const EUROPE_BERLIN = ZoneId.of('Europe/Berlin');
146+
const AMERICA_NEW_YORCK = ZoneId.of('America/New_York');
147+
148+
it('should equal in case of a local date with one valid offset at this zone', () => {
149+
150+
const testLocalToZoneEquality = [
151+
[LOCAL_DATE_IN_SUMMER, FIXED_ZONE_06, '2016-06-30T11:30:59.000000500+06:00'],
152+
[LOCAL_DATE_IN_SUMMER, ZoneOffset.UTC, '2016-06-30T11:30:59.000000500Z'],
153+
[LOCAL_DATE_IN_SUMMER, EUROPE_BERLIN, '2016-06-30T11:30:59.000000500+02:00[Europe/Berlin]'],
154+
[LOCAL_DATE_IN_WINTER, EUROPE_BERLIN, '2016-12-21T11:30:59.000000500+01:00[Europe/Berlin]'],
155+
[LOCAL_DATE_IN_SUMMER, AMERICA_NEW_YORCK, '2016-06-30T11:30:59.000000500-04:00[America/New_York]'],
156+
[LOCAL_DATE_IN_WINTER, AMERICA_NEW_YORCK, '2016-12-21T11:30:59.000000500-05:00[America/New_York]'],
157+
];
158+
159+
dataProviderTest(testLocalToZoneEquality, (localDateTime, zone, expectedZonedDateAsString) => {
160+
let zdt = ZonedDateTime.ofLocal(localDateTime, zone);
161+
expect(zdt.toString()).to.equal(expectedZonedDateAsString);
162+
});
163+
164+
});
165+
166+
it('should add zone offset for a local date with a gap at this zone', () => {
167+
168+
const testLocalToZoneEquality = [
169+
['2016-03-27T01:59', EUROPE_BERLIN, '2016-03-27T01:59+01:00[Europe/Berlin]'],
170+
// ['2016-03-27T02:00', EUROPE_BERLIN, '2016-03-27T03:00+02:00[Europe/Berlin]'],
171+
// ['2016-03-27T02:30', EUROPE_BERLIN, '2016-03-27T03:30+02:00[Europe/Berlin]'],
172+
['2016-03-27T03:00', EUROPE_BERLIN, '2016-03-27T03:00+02:00[Europe/Berlin]'],
173+
['2016-03-27T03:01', EUROPE_BERLIN, '2016-03-27T03:01+02:00[Europe/Berlin]'],
174+
['2016-03-13T01:59', AMERICA_NEW_YORCK, '2016-03-13T01:59-05:00[America/New_York]'],
175+
// ['2016-03-13T02:00', AMERICA_NEW_YORCK, '2016-03-13T03:00-04:00[America/New_York]'],
176+
// ['2016-03-13T02:30', AMERICA_NEW_YORCK, '2016-03-13T03:30-04:00[America/New_York]'],
177+
['2016-03-13T03:00', AMERICA_NEW_YORCK, '2016-03-13T03:00-04:00[America/New_York]'],
178+
['2016-03-13T03:01', AMERICA_NEW_YORCK, '2016-03-13T03:01-04:00[America/New_York]'],
179+
];
180+
181+
dataProviderTest(testLocalToZoneEquality, (localDateTimeAsString, zone, expectedZonedDateAsString) => {
182+
let ldt = LocalDateTime.parse(localDateTimeAsString);
183+
let zdt = ZonedDateTime.ofLocal(ldt, zone);
184+
expect(zdt.toString()).to.equal(expectedZonedDateAsString);
185+
});
186+
187+
});
188+
189+
it('should return the previous offset for a local date with an overlap at this zone', () => {
190+
191+
const testLocalToZoneEquality = () => {
192+
return [
193+
['2016-10-30T01:59', EUROPE_BERLIN, '2016-10-30T01:59+02:00[Europe/Berlin]'],
194+
// ['2016-10-30T02:00', EUROPE_BERLIN, '2016-10-30T02:00+02:00[Europe/Berlin]'],
195+
// ['2016-10-30T02:30', EUROPE_BERLIN, '2016-10-30T02:30+02:00[Europe/Berlin]'],
196+
['2016-10-30T03:00', EUROPE_BERLIN, '2016-10-30T03:00+01:00[Europe/Berlin]'],
197+
['2016-10-30T03:01', EUROPE_BERLIN, '2016-10-30T03:01+01:00[Europe/Berlin]'],
198+
['2016-11-06T00:59', AMERICA_NEW_YORCK, '2016-11-06T00:59-04:00[America/New_York]'],
199+
['2016-11-06T01:00', AMERICA_NEW_YORCK, '2016-11-06T01:00-04:00[America/New_York]'],
200+
['2016-11-06T01:30', AMERICA_NEW_YORCK, '2016-11-06T01:30-04:00[America/New_York]'],
201+
// ['2016-11-06T02:00', AMERICA_NEW_YORCK, '2016-11-06T02:00-05:00[America/New_York]'],
202+
['2016-11-06T02:01', AMERICA_NEW_YORCK, '2016-11-06T02:01-05:00[America/New_York]'],
203+
];
204+
};
205+
206+
dataProviderTest(testLocalToZoneEquality, (localDateTimeAsString, zone, expectedZonedDateAsString) => {
207+
let ldt = LocalDateTime.parse(localDateTimeAsString);
208+
let zdt = ZonedDateTime.ofLocal(ldt, zone);
209+
expect(zdt.toString()).to.equal(expectedZonedDateAsString);
210+
});
211+
212+
});
213+
214+
it('should return the preferred offset if specified in an overlap situation', () => {
215+
216+
const testLocalToZoneEquality = () => {
217+
return [
218+
['2016-10-30T02:30', EUROPE_BERLIN, ZoneOffset.ofHours(1)],
219+
// ['2016-10-30T02:30', EUROPE_BERLIN, ZoneOffset.ofHours(2)],
220+
['2016-11-06T01:30', AMERICA_NEW_YORCK, ZoneOffset.ofHours(-4)],
221+
// ['2016-11-06T01:30', AMERICA_NEW_YORCK, ZoneOffset.ofHours(-5)],
222+
];
223+
};
224+
225+
dataProviderTest(testLocalToZoneEquality, (localDateTimeAsString, zone, preferredOffset) => {
226+
let ldt = LocalDateTime.parse(localDateTimeAsString);
227+
let zdt = ZonedDateTime.ofLocal(ldt, zone, preferredOffset);
228+
expect(zdt.offset()).to.equal(preferredOffset);
229+
});
230+
231+
});
232+
233+
});
234+
140235
function createInstant(year, month, day, hour, min, zoneOffset) {
141236
return LocalDateTime.of(year, month, day, hour, min, 0).toInstant(zoneOffset);
142237
}

0 commit comments

Comments
 (0)