从格林尼治标准时间(GMT)到世界时间标准UTC

从格林尼治标准时间(GMT)到世界时间标准UTC
===

世界时间标准UTC

协调世界时(UTC)是当今的民用时间基准。这个24小时时间标准是通过高精度的原子钟结合地球自转来保持的。

标准,而非时区

UTC是世界通用的时间标准。世界各定时中心已经同意保持它们的时间尺度紧密同步 - 或协调 - 因此得名协调世界时。

原子时间和太阳时间

确定UTC使用了两个组成部分:

  • 国际原子时(TAI):结合全球约400台高精度原子钟的输出,提供我们时钟精确走时的速度。
  • 世界时(UT1):也称为天文时间或太阳时间,它指的是地球的自转。它用于比较TAI提供的速度与地球实际一天的长度。

UT始于1884年

世界时(UT)是在1884年的国际子午线会议上创建的。这是我们今天所知的24小时时区系统的基础。

当时,格林尼治标准时间(GMT)被选为世界的时间标准。参考线或起始点,即本初子午线,被确定为伦敦格林尼治皇家天文台的经过圈。经过圈是望远镜机械的一部分,至今仍被引用为本初子午线的原始参考(0°经度)。

从GMT到UTC

1960年,国际无线电咨询委员会正式规范了UTC的概念,并于次年付诸实践。协调世界时这个名称在1967年正式被采纳。

为什么是UTC - 而不是CUT或TUC?

UTC在1972年之前进行了多次调整,1972年引入了闰秒,以使UTC与地球的自转保持一致,因为地球的自转并不完全均匀,比原子钟不那么精确。

GMT现在是一个时区

直到1972年,格林尼治平均时间(也称为Z时)与世界时(UT)相同。

GMT和UTC之间的区别

从那时起,格林尼治平均时间不再是一个时间标准。今天,格林尼治平均时间(GMT)仅仅是一个时区的名称,在非洲和西欧的一些国家使用,包括英国在冬季和冰岛全年使用。

英国夏季使用英国夏令时间(BST),而不是GMT。

TimeZone ZoneOffset ZoneId ZoneInfo之间的关系

Java中的TimeZoneZoneOffsetZoneIdZoneInfo是用于处理时区信息的类。

它们之间的关系如下:

  1. TimeZone

    • TimeZone是Java早期用于表示时区信息的类,但已被新的Java时间API所取代。
    • TimeZone类提供了与时区和夏令时相关的信息,如偏移量、ID、名称等。
    • 旧的TimeZone类不够灵活,不支持Java 8的新日期时间API中的新功能。
  2. ZoneOffset

    • ZoneOffset是Java 8引入的类,用于表示与UTC或格林威治时间(GMT)的固定偏移量。
    • 例如,ZoneOffset.ofHours(2)表示与UTC时间相比偏移2小时的偏移量。
    • ZoneOffset不包含有关时区名称或夏令时调整的信息,只表示固定的时间偏移
  3. ZoneId

    • ZoneId是Java 8中用于表示时区标识符的类,可以表示特定的时区,如"Europe/Paris"或"Asia/Tokyo"。
    • ZoneId可以通过ZoneId.of("ZoneId")方法创建。
    • ZoneId可以表示具体的时区,与ZoneOffset相比,它可以处理更复杂的时区规则,如夏令时调整
  4. ZoneInfo

    • ZoneInfoZoneId的一个具体实现类,用于提供有关特定时区的详细信息。
    • ZoneInfo类实现了ZoneId接口,提供了更具体的时区信息,如时区偏移、规则和历史变化等。
    • ZoneInfo类通常用于获取关于特定时区的更详细信息。

总结来说,TimeZone是旧的时区类,ZoneOffset表示固定的时间偏移,ZoneId用于表示时区标识符,而ZoneInfoZoneId的一个具体实现,提供了更详细的时区信息。在Java应用程序中,通常建议使用新的Java 8时间API中的ZoneIdZoneOffset来处理时区信息,以获得更灵活和准确的时区处理功能。

代码示例1

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.util.Date;
import java.util.TimeZone;

public class TimeZoneExample {
   
    public static void main(String[] args) {
   
        String patternStr = "yyyy-MM-dd HH:mm:ss";
        // 北京时间(new出来就是默认时区的时间)
        Date bjDate = new Date();

        // 得到纽约的时区
        TimeZone newYorkTimeZone = TimeZone.getTimeZone("America/New_York");
        // 根据此时区 将北京时间转换为纽约的Date
        DateFormat newYorkDateFormat = new SimpleDateFormat(patternStr);
        newYorkDateFormat.setTimeZone(newYorkTimeZone);

        DateFormat newYorkDateFormat1 = new SimpleDateFormat(patternStr);

        System.out.println("这是北京时间:" + new SimpleDateFormat(patternStr).format(bjDate));
        System.out.println("这是纽约时间:" + newYorkDateFormat.format(bjDate));
        System.out.println("这是纽约时间:" + newYorkDateFormat1.format(bjDate));

    }
}

//这是北京时间:2024-04-22 23:19:53
//这是纽约时间:2024-04-22 11:19:53
//这是纽约时间:2024-04-22 23:19:53

代码示例2

import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class TimeZoneExample2 {
   

    public static void main(String[] args) {
   
        // 创建一个ZoneId表示"Asia/Tokyo"时区
        ZoneId tokyoZone = ZoneId.of("Asia/Tokyo");

        // 使用ZoneId获取当前时间
        ZonedDateTime tokyoTime = ZonedDateTime.now(tokyoZone);
        System.out.println("Current time in Tokyo: " + tokyoTime);

        // 创建一个ZoneOffset表示与UTC偏移5小时的时区
        ZoneOffset offset = ZoneOffset.ofHours(5);
        System.out.println("offset="+offset);

        // 使用ZoneOffset获取当前时间
        ZonedDateTime offsetTime = ZonedDateTime.now().plusHours(5);
        System.out.println("Current time with offset +5 hours: " + offsetTime);
    }
}
//Current time in Tokyo: 2024-04-22T23:58:15.236+09:00[Asia/Tokyo]
//offset=+05:00
//Current time with offset +5 hours: 2024-04-23T03:58:15.261+08:00[Asia/Shanghai]

AbstractCalendar

日历系统的抽象类AbstractCalendar,提供了日历系统的框枋。该类定义了许多抽象方法和常量,用于实现具体的日历系统。以下是源码的主要功能和结构:

  1. 定义了一些常量,如时间单位的毫秒表示(秒、分钟、小时、天)和公元1年1月1日到公元1970年1月1日的偏移量。
  2. 包含了抽象方法和实例方法,用于处理日历日期的转换、固定日期的计算以及时间的处理。
  3. 提供了日历纪元(Era)的获取、设置方法,用于处理纪元信息。
  4. 包含了获取、设置日历日期的方法,包括根据时间和时区计算日期、根据固定日期计算日历字段等。
  5. 实现了对日历日期的时间规范化和验证,确保日期时间的有效性。
  6. 包含了计算给定日期前后的星期几日期的方法,以及一些辅助方法用于处理时间。

总体来说,AbstractCalendar类提供了日历系统的基础框架,包括处理日期、时间、时区和纪元等功能。它是日历系统的抽象实现,具体的日历系统可以继承并实现其中的抽象方法以定制自己的日历系统。

/*
 * 此代码是基于系统默认时区获得的,在系统默认时区更改时,此方法的结果也会发生变化。
 * @return 区域ID,非null
 * @throws DateTimeException 如果转换后的区域ID格式无效
 * @throws ZoneRulesException 如果无法找到转换后的区域区域ID
 */
package sun.util.calendar;

import java.util.Locale;
import java.util.TimeZone;

/**
 * <code>AbstractCalendar</code>类为实现具体日历系统提供了框架。
 *
 * <p><a name="fixed_date"></a><B>固定日期</B><br>
 *
 * 要实现具体的日历系统,每个日历必须具有从周一,公元1年1月1日(公历)午夜开始的常规日期编号。
 * 在此类中,它被称为<I>固定日期</I>。公元1年1月1日(公历)是固定日期1。 (有关详细信息,请参见Nachum Dershowitz和Edward M. Reingold的<I>CALENDRICAL CALCULATION The Millennium Edition</I>,第1.2节。)
 *
 * @作者 Masayoshi Okutsu
 * @自1.5
 */
public abstract class AbstractCalendar extends CalendarSystem {
   

    // 常量假设没有闰秒支持。
    static final int SECOND_IN_MILLIS = 1000;
    static final int MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
    static final int HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
    static final int DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;

    // 公元1年1月1日和公元1970年1月1日之间的天数(公历)
    static final int EPOCH_OFFSET = 719163;

    private Era[] eras;

    protected AbstractCalendar() {
   
    }

    public Era getEra(String eraName) {
   
        if (eras != null) {
   
            for (int i = 0; i < eras.length; i++) {
   
                if (eras[i].equals(eraName)) {
   
                    return eras[i];
                }
            }
        }
        return null;
    }

    public Era[] getEras() {
   
        Era[] e = null;
        if (eras != null) {
   
            e = new Era[eras.length];
            System.arraycopy(eras, 0, e, 0, eras.length);
        }
        return e;
    }

    public void setEra(CalendarDate date, String eraName) {
   
        if (eras == null) {
   
            return; // should report an error???
        }
        for (int i = 0; i < eras.length; i++) {
   
            Era e = eras[i];
            if (e != null && e.getName().equals(eraName)) {
   
                date.setEra(e);
                return;
            }
        }
        throw new IllegalArgumentException("unknown era name: " + eraName);
    }

    protected void setEras(Era[] eras) {
   
        this.eras = eras;
    }

    public CalendarDate getCalendarDate() {
   
        return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
    }

    public CalendarDate getCalendarDate(long millis) {
   
        return getCalendarDate(millis, newCalendarDate());
    }

    public CalendarDate getCalendarDate(long millis, TimeZone zone) {
   
        CalendarDate date = newCalendarDate(zone);
        return getCalendarDate(millis, date);
    }

    public CalendarDate getCalendarDate(long millis, CalendarDate date) {
   
        int ms = 0;             // time of day
        int zoneOffset = 0;
        int saving = 0;
        long days = 0;          // fixed date

        // adjust to local time if `date' has time zone.
        TimeZone zi = date.getZone();
        if (zi != null) {
   
            int[] offsets = new int[2];
            if (zi instanceof ZoneInfo) {
   
                zoneOffset = ((ZoneInfo)zi).getOffsets(millis, offsets);
            } else {
   
                zoneOffset = zi.getOffset(millis);
                offsets[0] = zi.getRawOffset();
                offsets[1] = zoneOffset - offsets[0];
            }

            // We need to calculate the given millis and time zone
            // offset separately for java.util.GregorianCalendar
            // compatibility. (i.e., millis + zoneOffset could cause
            // overflow or underflow, which must be avoided.) Usually
            // days should be 0 and ms is in the range of -13:00 to
            // +14:00. However, we need to deal with extreme cases.
            days = zoneOffset / DAY_IN_MILLIS;
            ms = zoneOffset % DAY_IN_MILLIS;
            saving = offsets[1];
        }
        date.setZoneOffset(zoneOffset);
        date.setDaylightSaving(saving);

        days += millis / DAY_IN_MILLIS;
        ms += (int) (millis % DAY_IN_MILLIS);
        if (ms >= DAY_IN_MILLIS) {
   
            // at most ms is (DAY_IN_MILLIS - 1) * 2.
            ms -= DAY_IN_MILLIS;
            ++days;
        } else {
   
            // at most ms is (1 - DAY_IN_MILLIS) * 2. Adding one
            // DAY_IN_MILLIS results in still negative.
            while (ms < 0) {
   
                ms += DAY_IN_MILLIS;
                --days;
            }
        }

        // convert to fixed date (offset from Jan. 1, 1 (Gregorian))
        days += EPOCH_OFFSET;

        // calculate date fields from the fixed date
        getCalendarDateFromFixedDate(date, days);

        // calculate time fields from the time of day
        setTimeOfDay(date, ms);
        date.setLeapYear(isLeapYear(date));
        date.setNormalized(true);
        return date;
    }

    public long getTime(CalendarDate date) {
   
        long gd = getFixedDate(date);
        long ms = (gd - EPOCH_OFFSET) * DAY_IN_MILLIS + getTimeOfDay(date);
        int zoneOffset = 0;
        TimeZone zi = date.getZone();
        if (zi != null) {
   
            if (date.isNormalized()) {
   
                return ms - date.getZoneOffset();
            }
            // adjust time zone and daylight saving
            int[] offsets = new int[2];
            if (date.isStandardTime()) {
   
                // 1) 2:30am during starting-DST transition is
                //    intrepreted as 2:30am ST
                // 2) 5:00pm during DST is still interpreted as 5:00pm ST
                // 3) 1:30am during ending-DST transition is interpreted
                //    as 1:30am ST (after transition)
                if (zi instanceof ZoneInfo) {
   
                    ((ZoneInfo)zi).getOffsetsByStandard(ms, offsets);
                    zoneOffset = offsets[0];
                } else {
   
                    zoneOffset = zi.getOffset(ms - zi.getRawOffset());
                }
            } else {
   
                // 1) 2:30am during starting-DST transition is
                //    intrepreted as 3:30am DT
                // 2) 5:00pm during DST is intrepreted as 5:00pm DT
                // 3) 1:30am during ending-DST transition is interpreted
                //    as 1:30am DT/0:30am ST (before transition)
                if (zi instanceof ZoneInfo) {
   
                    zoneOffset = ((ZoneInfo)zi).getOffsetsByWall(ms, offsets);
                } else {
   
                    zoneOffset = zi.getOffset(ms - zi.getRawOffset());
                }
            }
        }
        ms -= zoneOffset;
        getCalendarDate(ms, date);
        return ms;
    }

    protected long getTimeOfDay(CalendarDate date) {
   
        long fraction = date.getTimeOfDay();
        if (fraction != CalendarDate.TIME_UNDEFINED) {
   
            return fraction;
        }
        fraction = getTimeOfDayValue(date);
        date.setTimeOfDay(fraction);
        return fraction;
    }

    public long getTimeOfDayValue(CalendarDate date) {
   
        long fraction = date.getHours();
        fraction *= 60;
        fraction += date.getMinutes();
        fraction *= 60;
        fraction += date.getSeconds();
        fraction *= 1000;
        fraction += date.getMillis();
        return fraction;
    }

    public CalendarDate setTimeOfDay(CalendarDate cdate, int fraction) {
   
        if (fraction < 0) {
   
            throw new IllegalArgumentException();
        }
        boolean normalizedState = cdate.isNormalized();
        int time = fraction;
        int hours = time / HOUR_IN_MILLIS;
        time %= HOUR_IN_MILLIS;
        int minutes = time / MINUTE_IN_MILLIS;
        time %= MINUTE_IN_MILLIS;
        int seconds = time / SECOND_IN_MILLIS;
        time %= SECOND_IN_MILLIS;
        cdate.setHours(hours);
        cdate.setMinutes(minutes);
        cdate.setSeconds(seconds);
        cdate.setMillis(time);
        cdate.setTimeOfDay(fraction);
        if (hours < 24 && normalizedState) {
   
            // If this time of day setting doesn't affect the date,
            // then restore the normalized state.
            cdate.setNormalized(normalizedState);
        }
        return cdate;
    }

    /**
     * 返回默认实现中的7。
     *
     * @return 7
     */
    public int getWeekLength() {
   
        return 7;
    }

    protected abstract boolean isLeapYear(CalendarDate date);

    public CalendarDate getNthDayOfWeek(int nth, int dayOfWeek, CalendarDate date) {
   
        CalendarDate ndate = (CalendarDate) date.clone();
        normalize(ndate);
        long fd = getFixedDate(ndate);
        long nfd;
        if (nth > 0) {
   
            nfd = 7 * nth + getDayOfWeekDateBefore(fd, dayOfWeek);
        } else {
   
            nfd = 7 * nth + getDayOfWeekDateAfter(fd, dayOfWeek);
        }
        getCalendarDateFromFixedDate(ndate, nfd);
        return ndate;
    }

    /**
     * 返回给定固定日期之前的给定星期几的日期。
     *
     * @param fixedDate 固定日期
     * @param dayOfWeek 星期几
     * @return 计算的日期
     */
    static long getDayOfWeekDateBefore(long fixedDate, int dayOfWeek) {
   
        return getDayOfWeekDateOnOrBefore(fixedDate - 1, dayOfWeek);
    }

    /**
     * 返回给定固定日期之后最接近的给定星期几的日期。
     *
     * @param fixedDate 固定日期
     * @param dayOfWeek 星期几
     * @return 计算的日期
     */
    static long getDayOfWeekDateAfter(long fixedDate, int dayOfWeek) {
   
        return getDayOfWeekDateOnOrBefore(fixedDate + 7, dayOfWeek);
    }

    /**
     * 返回给定固定日期上或之前的给定星期几的日期。
     *
     * @param fixedDate 固定日期
     * @param dayOfWeek 星期几
     * @return 计算的日期
     */
    // public for java.util.GregorianCalendar
    public static long getDayOfWeekDateOnOrBefore(long fixedDate, int dayOfWeek) {
   
        long fd = fixedDate - (dayOfWeek - 1);
        if (fd >= 0) {
   
            return fixedDate - (fd % 7);
        }
        return fixedDate - CalendarUtils.mod(fd, 7);
    }

    /**
     * 使用指定的日历日期计算固定日期。如果指定日期未标准化,则会标准化其日期字段。
     *
     * @param date 用于计算固定日期的<code>CalendarDate</code>
     * @return 计算的固定日期
     * @see AbstractCalendar.html#fixed_date
     */
    protected abstract long getFixedDate(CalendarDate date);

    /**
     * 从指定的固定日期计算日历字段。此方法将计算的日历字段值存储在指定的<code>CalendarDate</code>中。
     *
     * @param date 用于存储计算的日历字段的<code>CalendarDate</code>
     * @param fixedDate 用于计算日历字段的固定日期
     * @see AbstractCalendar.html#fixed_date
     */
    protected abstract void getCalendarDateFromFixedDate(CalendarDate date,
                                                         long fixedDate);

    public boolean validateTime(CalendarDate date) {
   
        int t = date.getHours();
        if (t < 0 || t >= 24) {
   
            return false;
        }
        t = date.getMinutes();
        if (t < 0 || t >= 60) {
   
            return false;
        }
        t = date.getSeconds();
        // TODO: Leap second support.
        if (t < 0 || t >= 60) {
   
            return false;
        }
        t = date.getMillis();
        if (t < 0 || t >= 1000) {
   
            return false;
        }
        return true;
    }


    int normalizeTime(CalendarDate date) {
   
        long fraction = getTimeOfDay(date);
        long days = 0;

        if (fraction >= DAY_IN_MILLIS) {
   
            days = fraction / DAY_IN_MILLIS;
            fraction %= DAY_IN_MILLIS;
        } else if (fraction < 0) {
   
            days = CalendarUtils.floorDivide(fraction, DAY_IN_MILLIS);
            if (days != 0) {
   
                fraction -= DAY_IN_MILLIS * days; // mod(fraction, DAY_IN_MILLIS)
            }
        }
        if (days != 0) {
   
            date.setTimeOfDay(fraction);
        }
        date.setMillis((int)(fraction % 1000));
        fraction /= 1000;
        date.setSeconds((int)(fraction % 60));
        fraction /= 60;
        date.setMinutes((int)(fraction % 60));
        date.setHours((int)(fraction / 60));
        return (int)days;
    }
}

TimeZone

TimeZone代表一个时区偏移,并能够确定夏令时。

通常情况下,您可以使用getDefault获取一个TimeZone,它会基于程序运行所在的时区创建一个TimeZone对象。

例如,对于在日本运行的程序,getDefault会创建一个基于日本标准时间的TimeZone对象。

您也可以使用getTimeZone以及一个时区ID来获取一个TimeZone

例如,美国太平洋时区的时区ID是"America/Los_Angeles"。所以,您可以通过以下方式获取一个美国太平洋时区的TimeZone对象:

TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");

您可以使用getAvailableIDs方法遍历所有支持的时区ID。然后您可以选择一个支持的ID来获取一个TimeZone

如果您想要的时区不在支持的ID中,则可以指定一个自定义的时区ID来生成一个TimeZone。

自定义时区ID的语法如下:

CustomID:
        <code>GMT</code> Sign Hours <code>:</code> Minutes
        <code>GMT</code> Sign Hours Minutes
        <code>GMT</code> Sign Hours
Sign: 其中之一
        <code>+ -</code>
Hours:
        Digit
        Digit Digit
Minutes:
        Digit Digit
Digit: 其中之一
        <code>0 1 2 3 4 5 6 7 8 9</code>

Hours必须在0到23之间,Minutes必须在00到59之间。例如,"GMT+10"和"GMT+0010"分别表示比GMT提前十小时和十分钟。

格式与语言环境无关,数字必须取自Unicode标准的基本拉丁文块。自定义时区ID中不能指定夏令时转换日程。

如果指定的字符串不匹配语法,"GMT"将被使用。

创建TimeZone时,指定的自定义时区ID将以以下语法规范化:

NormalizedCustomID:
        <code>GMT</code> Sign TwoDigitHours <code>:</code> Minutes
Sign: 其中之一
        <code>+ -</code>
TwoDigitHours:
        Digit Digit
Minutes:
        Digit Digit
Digit: 其中之一
        <code>0 1 2 3 4 5 6 7 8 9</code>

例如,TimeZone.getTimeZone(“GMT-8”).getID()返回"GMT-08:00"。

例如,TimeZone.getTimeZone(“GMT-8”).getID()返回"GMT-08:00"。

三字母时区ID

为了与JDK 1.1.x兼容,还支持一些其他三字母时区ID(例如"PST"、“CTT”、“AST”)。然而,它们的使用已被弃用,因为同一缩写通常用于多个时区(例如,“CST"可能是美国"中部标准时间"和"中国标准时间”),Java平台只能识别其中一个。

/**
 * <code>TimeZone</code>代表一个时区偏移,并能够确定夏令时。
 *
 * 通常情况下,您可以使用<code>getDefault</code>获取一个<code>TimeZone</code>,
 * 它会基于程序运行所在的时区创建一个<code>TimeZone</code>对象。例如,对于在日本运行的程序,
 * <code>getDefault</code>会创建一个基于日本标准时间的<code>TimeZone</code>对象。
 *
 * 您也可以使用<code>getTimeZone</code>以及一个时区ID来获取一个<code>TimeZone</code>。
 * 例如,美国太平洋时区的时区ID是"America/Los_Angeles"。所以,您可以通过以下方式获取一个美国太平洋时区的<code>TimeZone</code>对象:
 * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
 * 您可以使用<code>getAvailableIDs</code>方法遍历所有支持的时区ID。然后您可以选择一个支持的ID来获取一个<code>TimeZone</code>。
 * 如果您想要的时区不在支持的ID中,则可以指定一个自定义的时区ID来生成一个TimeZone。自定义时区ID的语法如下:
 * CustomID:
 *         <code>GMT</code> Sign Hours <code>:</code> Minutes
 *         <code>GMT</code> Sign Hours Minutes
 *         <code>GMT</code> Sign Hours
 * Sign: 其中之一
 *         <code>+ -</code>
 * Hours:
 *         Digit
 *         Digit Digit
 * Minutes:
 *         Digit Digit
 * Digit: 其中之一
 *         <code>0 1 2 3 4 5 6 7 8 9</code>
 *
 * Hours必须在0到23之间,Minutes必须在00到59之间。例如,"GMT+10"和"GMT+0010"分别表示比GMT提前十小时和十分钟。
 * 
 * 格式与语言环境无关,数字必须取自Unicode标准的基本拉丁文块。自定义时区ID中不能指定夏令时转换日程。如果指定的字符串不匹配语法,"GMT"将被使用。
 * 
 * 创建<code>TimeZone</code>时,指定的自定义时区ID将以以下语法规范化:
 * NormalizedCustomID:
 *         <code>GMT</code> Sign TwoDigitHours <code>:</code> Minutes
 * Sign: 其中之一
 *         <code>+ -</code>
 * TwoDigitHours:
 *         Digit Digit
 * Minutes:
 *         Digit Digit
 * Digit: 其中之一
 *         <code>0 1 2 3 4 5 6 7 8 9</code>
 * 例如,TimeZone.getTimeZone("GMT-8").getID()返回"GMT-08:00"。
 *
 * 三字母时区ID
 *
 * 为了与JDK 1.1.x兼容,还支持一些其他三字母时区ID(例如"PST"、"CTT"、"AST")。然而,它们的使用已被弃用,因为同一缩写通常用于多个时区(例如,"CST"可能是美国"中部标准时间"和"中国标准时间"),Java平台只能识别其中一个。
 *
 *
 * @see          Calendar
 * @see          GregorianCalendar
 * @see          SimpleTimeZone
 * @author       Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
 * @since        JDK1.1
 */
abstract public class TimeZone implements Serializable, Cloneable {
   
    /**
     * 唯一构造函数。(通常由子类构造函数隐式调用。)
     */
    public TimeZone() {
   
    }

    /**
     * 用于<code>getDisplayName()</code>的样式说明符,表示短名称,例如"PST"。
     * @see #LONG
     * @since 1.2
     */
    public static final int SHORT = 0;

    /**
     * 用于<code>getDisplayName()</code>的样式说明符,表示长名称,例如"Pacific Standard Time"。
     * @see #SHORT
     * @since 1.2
     */
    public static final int LONG  = 1;

    // 内部使用的常量;单位为毫秒
    private static final int ONE_MINUTE = 60*1000;
    private static final int ONE_HOUR   = 60*ONE_MINUTE;
    private static final int ONE_DAY    = 24*ONE_HOUR;

    // 声明与JDK 1.1的序列化兼容性
    static final long serialVersionUID = 3581463369166924961L;

    /**
     * 获取当前日期的时间区偏移,如果有夏令时,则进行修改。这是添加到UTC以获取本地时间的偏移量。
     * 
     * 此方法返回一个历史上正确的偏移量,如果底层的<code>TimeZone</code>实现子类支持历史夏令时安排和GMT偏移更改。
     *
     * @param era 给定日期的纪元。
     * @param year 给定日期的年份。
     * @param month 给定日期的月份。月份从0开始,例如,1代表一月。
     * @param day 给定日期的日期。
     * @param dayOfWeek 给定日期的星期几。
     * @param milliseconds <em>标准</em>本地时间一天中的毫秒数。
     *
     * @return 添加到GMT以获取本地时间的毫秒偏移量。
     *
     * @see Calendar#ZONE_OFFSET
     * @see Calendar#DST_OFFSET
     */
    public abstract int getOffset(int era, int year, int month, int day,
                                  int dayOfWeek, int milliseconds);

    /**
     * 返回此时区在指定日期的与UTC的偏移量。如果在指定日期执行夏令时,则偏移值将根据夏令时的量进行调整。
     * 
     * 此方法返回一个历史上正确的偏移值,如果底层TimeZone实现子类支持历史Daylight Saving Time安排和GMT偏移更改。
     *
     * @param date 表示自1970年1月1日00:00:00 GMT以来的毫秒数的日期。
     * @return 添加到UTC以获取本地时间的毫秒数。
     *
     * @see Calendar#ZONE_OFFSET
     * @see Calendar#DST_OFFSET
     * @since 1.4
     */
    public int getOffset(long date) {
   
        if (inDaylightTime(new Date(date
  • 18
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 格林尼治时间 (Greenwich Mean Time, GMT) 是指位于英国格林尼治的皇家标准时间,它是世界时间的基准。北京时间 (Beijing Time) 则是指中国大陆所使用的时区。北京时间格林尼治时间快 8 小时,也就是说,当格林尼治时间为星期二的上午 10 点时,北京时间同时为星期二的下午 6 点。 ### 回答2: 格林尼治时间GMT)和北京时间(CST)是两个不同的时间标准。 首先,格林尼治时间是由国际时间标准化组织设立的全球标准时间。它以英国的格林尼治天文台为参考点,被广泛用于航空、航海、科学研究等领域。格林尼治时间与地球自转速度相匹配,每天被分为24个小时。 而北京时间是中国的官方标准时间,主要用于中国的公共生活、政府机构和经济活动。北京时间格林尼治时间上推迟了8个小时,即北京时间相当于GMT时间的加8小时。 格林尼治时间基于地球的转动,是世界各地的时间的参考。相对而言,北京时间是根据中国地理边界以及国家所在的东八区设立的。这意味着北京时间在中国境内是唯一的时间标准,而格林尼治时间则被全球范围接受和使用。 此外,格林尼治时间不受夏令时的影响,保持不变。而北京时间则根据中国的夏令时政策,在每年的4月和10月进行调整。 总的来说,格林尼治时间是全球通用的时间标准,用于协调世界各地的时间。而北京时间是中国的官方标准时间,与格林尼治时间相差8个小时,并且受夏令时政策的影响。 ### 回答3: 格林尼治时间GMT)是世界时间的基准标准,以伦敦的观测为准,每天24小时不变。它不受夏令时等因素的影响,因此保持稳定。而北京时间(BJT)是中国标准时间,以中国的北京市为准,也是以24小时制表示。格林尼治时间和北京时间的区别如下: 1. 时区差异:格林尼治时间是全球统一的时间标准,位于零时区,而北京时间位于东八区,比格林尼治时间慢8小时。 2. 受夏令时影响:格林尼治时间不受夏令时的影响,每天都保持一致。而北京时间在1986年至1991年之间曾实行过夏令时,但目前已不再使用夏令时,因此一年四季保持不变。 3. 地理位置不同:格林尼治时间是根据英国伦敦的观测点设立的,而北京时间是根据中国北京市的地理位置设立的。 4. 应用范围:格林尼治时间被全球范围内的航空、航海、通信、天文学等领域广泛应用,作为世界各地时间的参考基准。而北京时间主要用于中国及中国相关领域的时间计算和标准。 总结来说,格林尼治时间是全球的统一参考时间,不受夏令时影响,而北京时间是中国的标准时间,受夏令时影响,并且比格林尼治时间慢8小时。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值