【问题标题】:Convert JavaScript Date from one timezone to the other?将 JavaScript 日期从一个时区转换为另一个时区?
【发布时间】:2026-01-20 16:15:02
【问题描述】:

我从服务器接收到带有时区规范的字符串格式 (ISO 8601) 的日期,例如:2014-12-14T21:00:00+0300

我需要将其转换为特定时区中的标准 JavaScript Date 对象,例如Europe/Moscow 关于夏令时等。

我尝试使用Moment.jsMoment Timezone 来实现这一点,但无济于事。

示例

var date = '2014-12-14T21:00:00+0300';
var timezone = 'Europe/Moscow';

var momentDate = moment.tz(date, timezone);
var jsDate = momentDate.toDate();

console.log(
    date,
    momentDate.format('DD.MM.YYYY HH:mm:ss ZZ'),
    jsDate
);

jsDate 仍在浏览器 (OS) 的本地时区中。

如何将 JavaScript Date 对象转换到另一个时区?

【问题讨论】:

    标签: javascript date timezone momentjs dst


    【解决方案1】:

    时区只是一个演示问题。

    Date 对象将始终采用 UTC,但当您将其转换为本地时区的字符串时,您的浏览器通常会调整输出。

    如果您希望将变量 jsDate 显示为以 不同 时区表示的字符串,那么您还必须使用类似 moment 的东西来执行该转换。

    【讨论】:

    • 那么浏览器将始终在其本地(OS)时区处理 Date 对象?没有办法改变吗?问题是我需要将此日期对象提供给第三方组件,并且我希望它在特定时区格式化日期。
    • 不,它总是存储它在UTC,但它会显示它在本地TZ。
    • 谢谢。看起来时区处理/日期格式应该在第三方组件级别上实现。
    • @SlavaFominII 这将是我的看法,是的。
    • @SlavaFominII - 如果你正在使用 moment,那么让它进行格式化。 Alnitak 是正确的——一旦你回到 Date 对象,你就将控制权恢复到浏览器——它将始终使用本地时区。
    【解决方案2】:

    正如 @Alnitak 所说,这是一个严格的演示问题。所有 JavaScript 日期都以 UTC 格式在内部存储,并在浏览器 (OS) 的本地时区进行操作。目标时区发挥作用的唯一地方是当您将 Date 对象转换为字符串以便将其显示给用户时。所有日期都将根据每个用户的本地时区进行格式化。

    但是,如果您想在某个特定时区格式化日期(例如,当您的用户在纽约并且您想在莫斯科显示日期时),您将不得不使用更高级的格式化实用程序,例如 Moment.js 和 @ 987654322@.

    当您控制应用程序中的所有日期格式时 - 这很容易实现。但是,当您需要将此功能传递给一些不关心时区等的第三方组件(例如某些 DatePicker 组件)时,它可能会变得非常丑陋。

    我发现解决此问题的唯一实用解决方案是创建一个标准的Date 对象,该对象假装在用户的本地时区。这是您可以使用的功能:

    /**
     * Returns standard Date from Moment.js date as if it was in local timezone.
     * Use getMoment() method of the result to get proper Moment.js date back.
     *
     * @param {object} momentDate
     *
     * @returns {Date}
     */
    function momentAsLocalDate(momentDate) {
    
        var origOffset = momentDate.format('ZZ');
        var localOffset = moment().format('ZZ');
    
        // Creating a standard date as if date was in current browser TZ.
        var stdDate = new Date(
            // Creating date from ISO:8601 format.
            momentDate.format('YYYY-MM-DDTHH:mm:ss') + localOffset
        );
    
        stdDate.getMoment = function() {
    
            function pad(number) {
                if (number < 10) {
                    return '0' + number;
                }
                return number;
            }
    
            // String in ISO:8601 format.
            var dateString =
                this.getFullYear() +
                '-' + pad(this.getMonth() + 1) +
                '-' + pad(this.getDate())      +
                'T' + pad(this.getHours())     +
                ':' + pad(this.getMinutes())   +
                ':' + pad(this.getSeconds())   +
                origOffset
            ;
    
            // Creating a new moment from date string.
            var momentDate = moment(dateString);
    
            // Setting original timezone.
            momentDate.zone(origOffset);
    
            return momentDate;
        };
    
        return stdDate;
    }
    

    这个函数的用法可以通过下面的简单测试来演示:

    /**
     * A stupid third-party component that doesn't care about timezones.
     *
     * @param {Date} inputDate
     */
    var thirdPartyComponent = function(inputDate) {
    
        // Showing date to a user.
        console.log('Here is the date: ' + inputDate);
    
        // Changing the date.
        inputDate.setHours(17, 30);
    
    };
    
    var momentDate = moment('2014-12-14T21:00:00+03:00').zone('+03:00');
    
    console.log('Original Moment Date', momentDate.format());
    
    var stdDate = momentAsLocalDate(momentDate);
    
    console.log('Converted Local Date', stdDate);
    
    thirdPartyComponent(stdDate);
    
    console.log('Changed Local Date', stdDate);
    
    console.log('Converted Moment Date', stdDate.getMoment().format());
    

    您将在控制台中得到以下结果:

    Original Moment Date 2014-12-14T21:00:00+03:00
    Converted Local Date Sun Dec 14 2014 21:00:00 GMT-0500 (EST)
    Here is the date: Sun Dec 14 2014 21:00:00 GMT-0500 (EST)
    Changed Local Date Sun Dec 14 2014 17:30:00 GMT-0500 (EST)
    Converted Moment Date 2014-12-14T17:30:00+03:00
    

    如果可以的话,我强烈建议不要在实践中使用这种方法。更好的做法是重写组件以支持时区或切换到更好的组件。但是,如果没有其他选择,请谨慎使用,风险自负。

    如果有更好的解决方案,或者这个例子可以改进 - 请告诉我。

    干杯!

    【讨论】:

    • 不错的尝试,但总的来说这不是一个好主意。您从 当前 日期收到 localOffset。对于被操纵的日期,这可能根本不是正确的偏移量。请记住夏令时,它针对不同的时区以不同方式实现。本地 DST 规则可能与目标时区一致,也可能不一致。最终,这里的功能并没有比已经内置到时刻和时刻时区的功能增加太多价值。 (仅作为建设性的批评)