介绍
我已经放弃了对这个新的和改进的代码的原始答案。我从头开始重写了所有内容。
程序不仅可以根据时区 id 设置时区,还可以解析 GMT 偏移小时和分钟。您甚至可以输入部分小时(带或不带分钟)!此代码非常动态,因为它使用正则表达式来解释 GMT 偏移时间。我试图尽可能全面。
以下输出由下面编写的代码生成。
Current time: Sat, Mar 22, 2014 07:12:22 PM EDT (GMT+00:00)
Enter a timezone: Africa/Cairo
Sun, Mar 23, 2014 01:12:22 AM EET (Eastern European Time)
Continue? (y/n): y
Enter a timezone: America/Los_Angeles
Sat, Mar 22, 2014 04:12:22 PM PDT (Pacific Standard Time)
Continue? (y/n): y
Enter a timezone: GMT-05:00
Sat, Mar 22, 2014 06:12:22 PM GMT-05:00 (GMT-05:00)
Continue? (y/n): y
Enter a timezone: GMT-4:30
Sat, Mar 22, 2014 06:42:22 PM GMT-04:30 (GMT-04:30)
Continue? (y/n): y
Enter a timezone: 8
Sun, Mar 23, 2014 07:12:22 AM GMT+08:00 (GMT+08:00)
Continue? (y/n): y
Enter a timezone: 11:30
Sun, Mar 23, 2014 10:42:22 AM GMT+11:30 (GMT+11:30)
Continue? (y/n): y
Enter a timezone: FooBar
[ERROR] Could not parse GMT ID!
[ERROR] Invalid GMT TimeZone ID!
Sun, Mar 23, 2014 10:42:22 AM GMT+11:30 (GMT+11:30)
Continue? (y/n): y
Enter a timezone: Asia/Tokyo
Sun, Mar 23, 2014 08:12:22 AM JST (Japan Standard Time)
Continue? (y/n): n
Done...
完整示例:
下面的代码应该可以满足您的要求以及更多!
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TimeZoneFormatter {
private static final DateFormat DEFAULT_DATE_FORMAT = new SimpleDateFormat("EEE, MMM d, yyyy hh:mm:ss a z");
private static final TimeZone GMT_TIME_ZONE = TimeZone.getTimeZone("GMT+00:00");
private static final Pattern GMT_PATTERN = Pattern.compile("(?:GMT)?([+-])?([012]?\\d)(:([0-5]?\\d))?");
private static final Pattern REMOVE_LEADING_ZEROS = Pattern.compile("^0+(?!$)");
private static final Set<String> VALID_IDS = new LinkedHashSet<String>(Arrays.asList(TimeZone.getAvailableIDs()));
private static final boolean DEBUG = true;
private DateFormat dateFormat;
private TimeZone timeZone;
public TimeZoneFormatter() {
this(DEFAULT_DATE_FORMAT);
}
public TimeZoneFormatter(DateFormat dateFormat) {
this.dateFormat = dateFormat;
this.timeZone = GMT_TIME_ZONE;
}
public void setDateFormat(DateFormat dateFormat) {
this.dateFormat = dateFormat;
}
public void setTimezone(boolean positive, int hours, int minutes) {
String timeZoneId = formatGmtId(positive, hours, minutes);
setTimezone(timeZoneId);
}
public void setTimezone(String timeZoneId) {
TimeZone newTimeZone = TimeZone.getTimeZone(timeZoneId);
if (timeZone.getRawOffset() != 0 && newTimeZone.getRawOffset() == 0) {
System.out.println("[ERROR] Invalid GMT TimeZone ID!");
} else {
timeZone = newTimeZone;
dateFormat.setTimeZone(timeZone);
}
}
public DateFormat getDateFormat() {
return dateFormat;
}
public String getTimezoneId() {
return timeZone.getID();
}
// -------------------------------------------------------------------------
// Begin internal parsing and formatting methods.
// -------------------------------------------------------------------------
private String parseGmtTimeZoneId(String id) {
Matcher m = GMT_PATTERN.matcher(id);
if (m.find()) {
char sign = m.group(1) != null ? m.group(1).charAt(0) : '+';
int hours = removeLeadingZeros(m.group(2));
int minutes = 0;
if (m.group(3) != null) {
minutes = removeLeadingZeros(m.group(4));
}
return formatGmtId(sign, hours, minutes);
}
if (!VALID_IDS.contains(id)) {
System.out.println("[ERROR] Could not parse GMT ID!");
}
return id;
}
private void setGmtTimezone(String gmtOffset) {
String timeZoneId = parseGmtTimeZoneId(gmtOffset);
setTimezone(timeZoneId);
}
private String formatGmtId(boolean positive, int hours, int minutes) {
return formatGmtId(positive ? '+' : '-', hours, minutes);
}
private String formatGmtId(char sign, int hours, int minutes) {
return String.format("GMT%c%02d:%02d", sign, hours, minutes);
}
private int removeLeadingZeros(String intStr) {
return Integer.parseInt(intStr.replaceAll(REMOVE_LEADING_ZEROS.pattern(), ""));
}
private String formatDate(final Date time) {
return String.format("%s (%s)", dateFormat.format(time),
timeZone.getDisplayName());
}
// -------------------------------------------------------------------------
// Begin main method and other static utility methods.
// -------------------------------------------------------------------------
public static void main(String[] args) {
if (DEBUG) {
printAllAvailableTimeZones();
}
final Date time = new Date();
TimeZoneFormatter frmt = new TimeZoneFormatter();
Scanner scan = new Scanner(System.in);
try {
System.out.printf("Current time: ");
printDate(time, frmt);
while (true) {
System.out.print("Enter a timezone: ");
frmt.setGmtTimezone(scan.nextLine());
printDate(time, frmt);
System.out.print("Continue? (y/n): ");
String response = scan.nextLine().trim();
if ((response.length() < 1 ? 'y' : response.charAt(0)) == 'n') {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
scan.close();
}
System.out.println("Done...");
}
public static void printDate(final Date date, TimeZoneFormatter formatter) {
if (date == null) {
throw new IllegalArgumentException("Please enter a non-null date.");
}
if (formatter == null) {
formatter = new TimeZoneFormatter();
}
System.out.println(formatter.formatDate(date));
}
public static void printAllAvailableTimeZones() {
System.out.println("Available Time Zones:");
List<TimeZone> timeZones = new ArrayList<TimeZone>();
for (String id : VALID_IDS) {
timeZones.add(TimeZone.getTimeZone(id));
}
Collections.sort(timeZones, new Comparator<TimeZone>() {
@Override
public int compare(TimeZone t1, TimeZone t2) {
int offsetDiff = t1.getRawOffset() - t2.getRawOffset();
if (offsetDiff == 0) {
int nameDiff = t1.getDisplayName().compareTo(t2.getDisplayName());
if (nameDiff == 0) {
return t1.getID().compareTo(t2.getID());
} else {
return nameDiff;
}
} else {
return offsetDiff;
}
}
});
for (TimeZone timeZone : timeZones) {
System.out.printf("%s : %32s : %s%n", getFormattedOffset(timeZone),
timeZone.getID(), timeZone.getDisplayName());
}
System.out.println();
}
private static String getFormattedOffset(TimeZone timeZone) {
int offset = timeZone.getRawOffset();
char sign = offset < 0 ? '-' : '+';
if (offset < 0) {
offset *= -1;
}
int hours = offset / 3600000;
int mins = (offset % 3600000) / 60000;
return String.format("%c%02d:%02d", sign, hours, mins);
}
}
打印时区偏移和显示名称:
这是所有比格林威治标准时间晚 5 小时的时区的快速打印输出。这可以通过调用printAllAvailableTimeZones()
方法来实现。这是在调试模式下自动调用的。
-05:00 : America/Bogota : Colombia Time
-05:00 : America/Havana : Cuba Standard Time
-05:00 : Cuba : Cuba Standard Time
-05:00 : America/Atikokan : Eastern Standard Time
-05:00 : America/Cayman : Eastern Standard Time
-05:00 : America/Coral_Harbour : Eastern Standard Time
-05:00 : America/Detroit : Eastern Standard Time
-05:00 : America/Fort_Wayne : Eastern Standard Time
-05:00 : America/Grand_Turk : Eastern Standard Time
-05:00 : America/Indiana/Indianapolis : Eastern Standard Time
-05:00 : America/Indiana/Marengo : Eastern Standard Time
-05:00 : America/Indiana/Petersburg : Eastern Standard Time
-05:00 : America/Indiana/Vevay : Eastern Standard Time
-05:00 : America/Indiana/Vincennes : Eastern Standard Time
-05:00 : America/Indiana/Winamac : Eastern Standard Time
-05:00 : America/Indianapolis : Eastern Standard Time
-05:00 : America/Iqaluit : Eastern Standard Time
-05:00 : America/Jamaica : Eastern Standard Time
-05:00 : America/Kentucky/Louisville : Eastern Standard Time
-05:00 : America/Kentucky/Monticello : Eastern Standard Time
-05:00 : America/Louisville : Eastern Standard Time
-05:00 : America/Montreal : Eastern Standard Time
-05:00 : America/Nassau : Eastern Standard Time
-05:00 : America/New_York : Eastern Standard Time
-05:00 : America/Nipigon : Eastern Standard Time
-05:00 : America/Panama : Eastern Standard Time
-05:00 : America/Pangnirtung : Eastern Standard Time
-05:00 : America/Port-au-Prince : Eastern Standard Time
-05:00 : America/Thunder_Bay : Eastern Standard Time
-05:00 : America/Toronto : Eastern Standard Time
-05:00 : Canada/Eastern : Eastern Standard Time
-05:00 : EST : Eastern Standard Time
-05:00 : EST5EDT : Eastern Standard Time
-05:00 : IET : Eastern Standard Time
-05:00 : Jamaica : Eastern Standard Time
-05:00 : SystemV/EST5 : Eastern Standard Time
-05:00 : SystemV/EST5EDT : Eastern Standard Time
-05:00 : US/East-Indiana : Eastern Standard Time
-05:00 : US/Eastern : Eastern Standard Time
-05:00 : US/Michigan : Eastern Standard Time
-05:00 : America/Guayaquil : Ecuador Time
-05:00 : Etc/GMT+5 : GMT-05:00
-05:00 : America/Lima : Peru Time
其他资源:
以下 Oracle 教程:时区和偏移类可以帮助您进一步解决问题。
ZoneId 和 ZoneOffset
Date-Time API 提供了两个类用于指定时区或偏移量:
- ZoneId 指定时区标识符并提供在 Instant 和 LocalDateTime 之间转换的规则。
- ZoneOffset 指定与格林威治/UTC 时间的时区偏移量。