Skip to content
Merged
4 changes: 2 additions & 2 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ requirejs(["luxon"], function(luxon) {

## ES6

- [Download full](https://moment.github.io/luxon/es6/luxon.js)
- [Download minified](https://moment.github.io/luxon/es6/luxon.min.js)
- [Download full](https://moment.github.io/luxon/es6/luxon.mjs)
- [Download minified](https://moment.github.io/luxon/es6/luxon.min.mjs)

```js
import { DateTime } from "luxon";
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"uglify-js": "^3.13.10"
},
"main": "build/node/luxon.js",
"module": "src/luxon.js",
"module": "build/es6/luxon.mjs",
"browser": "build/cjs-browser/luxon.js",
"jsdelivr": "build/global/luxon.min.js",
"unpkg": "build/global/luxon.min.js",
Expand Down
32 changes: 20 additions & 12 deletions site/plugins/dark-theme-toggle.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#docsify-dark-theme-toggle {
.docsify-dark-theme-toggle {
position: absolute;
display: inline-block;
width: 52px;
Expand All @@ -13,30 +13,38 @@
.sidebar > .app-name {
position: relative;
}
.app-name > #docsify-dark-theme-toggle {
.app-name > .docsify-dark-theme-toggle {
margin-right: 1rem;
margin-top: 0;
right: 0;
left: unset;
transition: opacity 250ms ease, visibility 250ms steps(1, jump-both);
opacity: 0;
visibility: hidden;
}
.sticky .app-name > .docsify-dark-theme-toggle {
opacity: 1;
visibility: visible;
}
#docsify-dark-theme-toggle::before, #docsify-dark-theme-toggle::after {

.docsify-dark-theme-toggle::before, .docsify-dark-theme-toggle::after {
position: absolute;
top: 0.1em;
font-size: 16px;
transition: opacity 0.3s;
}
#docsify-dark-theme-toggle::before {
.docsify-dark-theme-toggle::before {
content: "🌙";
left: 0.1em;
opacity: 0;
z-index: 1;
}
#docsify-dark-theme-toggle::after {
.docsify-dark-theme-toggle::after {
content: "🌞";
right: 0.1em;
opacity: 1;
}
#docsify-dark-theme-toggle > span {
.docsify-dark-theme-toggle > span {
position: absolute;
top: 0;
left: 0;
Expand All @@ -46,7 +54,7 @@
border-radius: 28px;
transition: background-color 0.3s;
}
#docsify-dark-theme-toggle > span::before {
.docsify-dark-theme-toggle > span::before {
content: "";
position: absolute;
height: 22px;
Expand All @@ -58,15 +66,15 @@
border-radius: 50%;
transition: transform 0.3s;
}
.dark #docsify-dark-theme-toggle::after {
.dark .docsify-dark-theme-toggle::after {
opacity: 0;
}
.dark #docsify-dark-theme-toggle::before {
.dark .docsify-dark-theme-toggle::before {
opacity: 1;
}
.dark #docsify-dark-theme-toggle > span {
.dark .docsify-dark-theme-toggle > span {
background-color: var(--theme-color, #ea6f5a);
}
.dark #docsify-dark-theme-toggle > span::before {
.dark .docsify-dark-theme-toggle > span::before {
transform: translateX(24px);
}
}
15 changes: 11 additions & 4 deletions site/plugins/dark-theme-toggle.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,25 @@
const TOGGLE_ID = "docsify-dark-theme-toggle",
dom = Docsify.dom,
darkThemeStyleSheet = dom.find('link[href$="dark.css"]'),
toggleEl = dom.create("div", "<span />"),
applyTheme = (swap = false) => {
const isDark = Boolean(swap ^ (localStorage[TOGGLE_ID] == "true"));
localStorage[TOGGLE_ID] = isDark;
darkThemeStyleSheet.disabled = !isDark;
dom.toggleClass(dom.body, isDark ? "add" : "remove", "dark");
};
localStorage[TOGGLE_ID] ??= matchMedia("(prefers-color-scheme: dark)").matches;
toggleEl.id = TOGGLE_ID;
dom.on(toggleEl, "click", () => applyTheme(true));
hook.init(applyTheme);
hook.doneEach(() => dom.before(dom.find(".cover.show, .sidebar > .app-name"), toggleEl));
hook.doneEach(() => {
dom.findAll(".cover.show, .sidebar > .app-name").forEach((target) => {
let toggleEl = dom.find(target, `.${TOGGLE_ID}`);
if (null == toggleEl) {
toggleEl = dom.create("div", "<span />");
toggleEl.className = TOGGLE_ID;
dom.on(toggleEl, "click", () => applyTheme(true));
}
dom.before(target, toggleEl);
});
});
};
$docsify ??= {};
$docsify.plugins = [...($docsify.plugins ?? []), darkThemeTogglePlugin];
Expand Down
83 changes: 59 additions & 24 deletions src/datetime.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ function unsupportedZone(zone) {

// we cache week data on the DT object and this intermediates the cache
/**
* @ignore
* @param {DateTime} dt
*/
function possiblyCachedWeekData(dt) {
Expand All @@ -70,6 +71,7 @@ function possiblyCachedWeekData(dt) {
}

/**
* @ignore
* @param {DateTime} dt
*/
function possiblyCachedLocalWeekData(dt) {
Expand All @@ -93,6 +95,7 @@ function clone(inst, alts) {
o: inst.o,
loc: inst.loc,
invalid: inst.invalid,
wasHole: inst.wasHole,
};
return new DateTime({ ...current, ...alts, old: current });
}
Expand All @@ -108,7 +111,7 @@ function fixOffset(localTS, o, tz) {

// If so, offset didn't change and we're done
if (o === o2) {
return [utcGuess, o];
return [utcGuess, o, false];
}

// If not, change the ts by the difference in the offset
Expand All @@ -117,11 +120,11 @@ function fixOffset(localTS, o, tz) {
// If that gives us the local time we want, we're done
const o3 = tz.offset(utcGuess);
if (o2 === o3) {
return [utcGuess, o2];
return [utcGuess, o2, false];
}

// If it's different, we're in a hole time. The offset has changed, but the we don't adjust the time
return [localTS - Math.min(o2, o3) * 60 * 1000, Math.max(o2, o3)];
return [localTS - Math.min(o2, o3) * 60 * 1000, Math.max(o2, o3), true];
}

// convert an epoch timestamp into a calendar object with the given offset
Expand Down Expand Up @@ -173,15 +176,15 @@ function adjustTime(inst, dur) {
}).as("milliseconds"),
localTS = objToLocalTS(c);

let [ts, o] = fixOffset(localTS, oPre, inst.zone);
let [ts, o, wasHole] = fixOffset(localTS, oPre, inst.zone);

if (millisToAdd !== 0) {
ts += millisToAdd;
// that could have changed the offset by going over a DST, but we want to keep the ts the same
o = inst.zone.offset(ts);
}

return { ts, o };
return { ts, o, wasHole };
}

// helper useful in turning the results of parsing into real dates
Expand Down Expand Up @@ -410,6 +413,7 @@ function normalizeUnitWithLocalWeeks(unit) {
/**
* @param {Zone} zone
* @return {number}
* @ignore
*/
function guessOffsetForZone(zone) {
if (zoneOffsetTs === undefined) {
Expand Down Expand Up @@ -441,7 +445,7 @@ function quickDT(obj, opts) {

const loc = Locale.fromObject(opts);

let ts, o;
let ts, o, wasHole;

// assume we have the higher-order units
if (!isUndefined(obj.year)) {
Expand All @@ -457,12 +461,12 @@ function quickDT(obj, opts) {
}

const offsetProvis = guessOffsetForZone(zone);
[ts, o] = objToTS(obj, offsetProvis, zone);
[ts, o, wasHole] = objToTS(obj, offsetProvis, zone);
} else {
ts = Settings.now();
}

return new DateTime({ ts, zone, loc, o });
return new DateTime({ ts, zone, loc, o, wasHole });
}

function diffRelative(start, end, opts) {
Expand Down Expand Up @@ -510,13 +514,16 @@ function lastOpts(argList) {

/**
* Timestamp to use for cached zone offset guesses (exposed for test)
* @ignore
*/
let zoneOffsetTs;
/**
* Cache for zone offset guesses (exposed for test).
*
* This optimizes quickDT via guessOffsetForZone to avoid repeated calls of
* zone.offset().
*
* @ignore
*/
const zoneOffsetGuessCache = new Map();

Expand All @@ -535,7 +542,7 @@ const zoneOffsetGuessCache = new Map();
* {@link DateTime#day}, {@link DateTime#hour}, {@link DateTime#minute}, {@link DateTime#second}, {@link DateTime#millisecond} accessors.
* * **Week calendar**: For ISO week calendar attributes, see the {@link DateTime#weekYear}, {@link DateTime#weekNumber}, and {@link DateTime#weekday} accessors.
* * **Configuration** See the {@link DateTime#locale} and {@link DateTime#numberingSystem} accessors.
* * **Transformation**: To transform the DateTime into other DateTimes, use {@link DateTime#set}, {@link DateTime#reconfigure}, {@link DateTime#setZone}, {@link DateTime#setLocale}, {@link DateTime.plus}, {@link DateTime#minus}, {@link DateTime#endOf}, {@link DateTime#startOf}, {@link DateTime#toUTC}, and {@link DateTime#toLocal}.
* * **Transformation**: To transform the DateTime into other DateTimes, use {@link DateTime#set}, {@link DateTime#reconfigure}, {@link DateTime#setZone}, {@link DateTime#setLocale}, {@link DateTime#plus}, {@link DateTime#minus}, {@link DateTime#endOf}, {@link DateTime#startOf}, {@link DateTime#toUTC}, and {@link DateTime#toLocal}.
* * **Output**: To convert the DateTime to other representations, use the {@link DateTime#toRelative}, {@link DateTime#toRelativeCalendar}, {@link DateTime#toJSON}, {@link DateTime#toISO}, {@link DateTime#toHTTP}, {@link DateTime#toObject}, {@link DateTime#toRFC2822}, {@link DateTime#toString}, {@link DateTime#toLocaleString}, {@link DateTime#toFormat}, {@link DateTime#toMillis} and {@link DateTime#toJSDate}.
*
* There's plenty others documented below. In addition, for more information on subtler topics like internationalization, time zones, alternative calendars, validity, and so on, see the external documentation.
Expand All @@ -556,13 +563,14 @@ export default class DateTime {
*/
this.ts = isUndefined(config.ts) ? Settings.now() : config.ts;

let c = null,
o = null;
let c = null;
let o = null;
if (!invalid) {
const unchanged = config.old && config.old.ts === this.ts && config.old.zone.equals(zone);

if (unchanged) {
[c, o] = [config.old.c, config.old.o];
c = config.old.c;
o = config.old.o;
} else {
// If an offset has been passed and we have not been called from
// clone(), we can trust it and avoid the offset calculation.
Expand Down Expand Up @@ -598,9 +606,12 @@ export default class DateTime {
* @access private
*/
this.c = c;

/**
* @access private
*/
this._wasHole = config.wasHole || false;

this.o = o;
/**
* @access private
Expand Down Expand Up @@ -873,16 +884,18 @@ export default class DateTime {

// compute the actual time
const gregorian = useWeekData
? weekToGregorian(normalized, minDaysInFirstWeek, startOfWeek)
: containsOrdinal
? ordinalToGregorian(normalized)
: normalized,
[tsFinal, offsetFinal] = objToTS(gregorian, offsetProvis, zoneToUse),
? weekToGregorian(normalized, minDaysInFirstWeek, startOfWeek)
: containsOrdinal
? ordinalToGregorian(normalized)
: normalized;

const [tsFinal, offsetFinal, wasHole] = objToTS(gregorian, offsetProvis, zoneToUse),
inst = new DateTime({
ts: tsFinal,
zone: zoneToUse,
o: offsetFinal,
loc,
wasHole,
});

// gregorian data + weekday serves only to validate
Expand Down Expand Up @@ -1168,6 +1181,19 @@ export default class DateTime {
return this.isValid ? this.zone.name : null;
}

/**
* Whether this DateTime was created from a "hole time" that can exist during DST due to the
* clocks moving forward.
*
* @example DateTime.local(2017, 3, 12, 2).wasHole; //=> true
* @example DateTime.local(2017, 3, 12, 4).wasHole; //=> false
*
* @return {boolean}
*/
get wasHole() {
return this._wasHole;
}

/**
* Get the year
* @example DateTime.local(2017, 5, 25).year //=> 2017
Expand Down Expand Up @@ -1571,23 +1597,32 @@ export default class DateTime {
return DateTime.invalid(unsupportedZone(zone));
} else {
let newTS = this.ts;
let wasHole = false;
if (keepLocalTime || keepCalendarTime) {
const offsetGuess = zone.offset(this.ts);
const asObj = this.toObject();
[newTS] = objToTS(asObj, offsetGuess, zone);
[newTS, , wasHole] = objToTS(asObj, offsetGuess, zone);
}
return clone(this, { ts: newTS, zone });
return clone(this, { ts: newTS, zone, wasHole });
}
}

/**
* "Set" the locale, numberingSystem, or outputCalendar. Returns a newly-constructed DateTime.
* "Set" the locale, numberingSystem, outputCalendar, or weekSettings. Returns a newly-constructed DateTime.
* @param {Object} properties - the properties to set
* @param {string} [properties.locale] - the locale to set
* @param {string} [properties.numberingSystem] - the numbering system to set
* @param {string} [properties.outputCalendar] - the output calendar to set
* @param {Object} [properties.weekSettings] - the week settings to set
* @param {number} [properties.weekSettings.firstDay] - the first day of the week (1-7, Monday-Sunday)
* @param {number} [properties.weekSettings.minimalDays] - the minimum number of days in the first week
* @param {number[]} [properties.weekSettings.weekend] - the weekend days
* @example DateTime.local(2017, 5, 25).reconfigure({ locale: 'en-GB' })
* @example DateTime.local(2017, 5, 25).reconfigure({ weekSettings: { firstDay: 1 } })
* @return {DateTime}
*/
reconfigure({ locale, numberingSystem, outputCalendar } = {}) {
const loc = this.loc.clone({ locale, numberingSystem, outputCalendar });
reconfigure({ locale, numberingSystem, outputCalendar, weekSettings } = {}) {
const loc = this.loc.clone({ locale, numberingSystem, outputCalendar, weekSettings });
return clone(this, { loc });
}

Expand Down Expand Up @@ -1659,8 +1694,8 @@ export default class DateTime {
}
}

const [ts, o] = objToTS(mixed, this.o, this.zone);
return clone(this, { ts, o });
const [ts, o, wasHole] = objToTS(mixed, this.o, this.zone);
return clone(this, { ts, o, wasHole });
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/impl/conversions.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export function ordinalToGregorian(ordinalData) {
* If so, validates that they are not mixed with ISO week units and then copies them to the normal week unit properties.
* Modifies obj in-place!
* @param obj the object values
* @ignore
*/
export function usesLocalWeekValues(obj, loc) {
const hasLocaleWeekData =
Expand Down
Loading
Loading