代码之家  ›  专栏  ›  技术社区  ›  matt b

从字符串中提取时区对象的最佳方法?

  •  8
  • matt b  · 技术社区  · 17 年前

    我有一个包含原始日期字段(存储为字符数据)的数据库字段,例如

    2008年9月26日星期五东部夏时制时间晚上8:30

    我可以用simpleDateFormat轻松地将其解析为日期

    DateFormat dbFormatter = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz");
    Date scheduledDate = dbFormatter.parse(rawDate);
    

    我想做的是从这个字符串中提取一个时区对象。这个应用程序运行的jvm中的默认时区是gmt,所以我不能使用 .getTimezoneOffset() Date 上面分析过(因为它将返回默认时区)。

    除了标记原始字符串和查找时区字符串的起始位置(因为我知道格式将始终是 EEEE, MMMM dd, yyyy hh:mm aa zzzz )有没有一种方法可以使用dateformat/simpledateformat/date/calendar api来提取时区对象-它将与我解析的字符串具有相同的时区 DateFormat.parse() ?

    有件事让我讨厌 日期 VS Calendar 在Java API中是 历法 应该会取代 日期 在所有地方…但后来他们决定 日期 在里面 DateFormat 类。

    7 回复  |  直到 9 年前
        1
  •  2
  •   Ed Thomas    9 年前

    我发现如下:

            DateFormat dbFormatter = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz");
            dbFormatter.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
            Date scheduledDate = dbFormatter.parse("Friday, September 26, 2008 8:30 PM Eastern Daylight Time");
            System.out.println(scheduledDate);
            System.out.println(dbFormatter.format(scheduledDate));
            TimeZone tz = dbFormatter.getTimeZone();
            System.out.println(tz.getDisplayName());
            dbFormatter.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
            System.out.println(dbFormatter.format(scheduledDate));
    

    产生以下结果:

    Fri Sep 26 20:30:00 CDT 2008
    Friday, September 26, 2008 08:30 PM Eastern Standard Time
    Eastern Standard Time
    Friday, September 26, 2008 08:30 PM Central Daylight Time
    

    我真的觉得这有点奇怪。但是,我想这表明,对您的问题的答案是,在解析之后,只需在格式化程序上调用gettimezone。

    编辑: 上面是用sun的jdk 1.6运行的。

        2
  •  1
  •   matt b    17 年前

    @ Ed Thomas:

    我尝试了一些与你的例子非常相似的方法,得到了非常不同的结果:

    String testString = "Friday, September 26, 2008 8:30 PM Pacific Standard Time";
    DateFormat df = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz");
    
    System.out.println("The default TimeZone is: " + TimeZone.getDefault().getDisplayName());
    
    System.out.println("DateFormat timezone before parse: " + df.getTimeZone().getDisplayName());
    
    Date date = df.parse(testString);
    
    System.out.println("Parsed [" + testString + "] to Date: " + date);
    
    System.out.println("DateFormat timezone after parse: " + df.getTimeZone().getDisplayName());
    

    输出:

    默认时区为:东部标准时间

    dateformat分析前时区:东部标准时间

    解析时间[2008年9月26日星期五,太平洋标准时间晚上8:30]截止日期:2008年9月27日星期六,美国东部时间00:30:00

    解析后的日期格式时区:东部标准时间

    好像 DateFormat.getTimeZone() 返回 parse() …即使我把一个 setTimeZone() 打电话之前 PARSE() .

    查看dateformat和simpledateformat的源代码,似乎 getTimeZone() 只需返回基础日历的时区…它将默认为默认区域设置/时区的日历,除非指定要使用的日历。

        3
  •  1
  •   Aaron    17 年前

    我建议你去看看 Joda时间日期和时间API . 我最近被转换为它的信徒,因为它往往比Java中的日期和时间的内置支持优越得多。特别是,你应该看看 达蒂梅区 班级。希望这有帮助。

    http://joda-time.sourceforge.net/

    http://joda-time.sourceforge.net/api-release/index.html

        4
  •  1
  •   Community Mohan Dere    9 年前

    DR

    ZonedDateTime.parse( 
        "Friday, September 26, 2008 8:30 PM Eastern Daylight Time" , 
        DateTimeFormatter.ofPattern( "EEEE, MMMM d, uuuu h:m a zzzz" ) 
    ).getZone()
    

    Java.时间

    现代的方法是使用java.time类。问题和其他答案使用麻烦的旧遗留日期时间类或joda时间项目,这两个类现在都被java.time类所取代。

    定义一个 DateTimeFormatter 具有与数据匹配的格式模式的。

    DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEEE, MMMM d, uuuu h:m a zzzz" );
    

    分配一个 Locale 指定人名日和月的名称,以及其他格式问题的文化规范。

    f = f.withLocale( Locale.US );
    

    最后,进行解析以获得 ZonedDateTime 对象。

    String input = "Friday, September 26, 2008 8:30 PM Eastern Daylight Time" ;
    ZonedDateTime zdt = ZonedDateTime.parse( input , f );
    

    zdt.tostring():2008-09-26t20:30-04:00[美国/纽约]

    你可以从 分区日期 ,表示为 ZoneId 对象。然后你可以审问 佐尼 如果你需要更多关于时区的信息。

    ZoneId z = zdt.getZone();
    

    See for yourself in IdeOne.com .

    国际标准化组织8601

    避免以这种方式交换日期时间数据 可怕的 格式。不要使用英语,不要用诸如天的名字之类的东西来修饰你的输出,也不要使用诸如 Eastern Daylight Time .

    对于时区:指定 proper time zone name 格式为 continent/region ,如 America/Montreal , Africa/Casablanca Pacific/Auckland . 切勿使用3-4个字母的缩写,如 EST IST 因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!).

    若要将日期时间值序列化为文本,请仅使用 ISO 8601 格式。默认情况下,java.time类在解析/生成字符串以表示其值时使用这些格式。


    关于java.time

    这个 java.time 框架是在Java 8和之后构建的。这些类取代了麻烦的旧类 legacy 日期时间类,如 java.util.Date , Calendar 和; SimpleDateFormat .

    这个 Joda-Time 项目,现在在 maintenance mode ,建议迁移到java.time。

    要了解更多信息,请参阅 Oracle Tutorial . 和搜索堆栈溢出的许多例子和解释。规格是 JSR 310 .

    在哪里获得java.time类?

    这个 ThreeTen-Extra project使用其他类扩展java.time。这个项目是将来可能添加java.time的一个试验场。你可以在这里找到一些有用的类,比如 Interval , YearWeek , YearQuarter more .

        5
  •  0
  •   Mitchel Sellers    17 年前

    作为一个部分解决方案,您可以使用regex匹配来获取时区,因为您将始终在它前面有相同的文本。AM或PM。

    我对Java时区的了解还不够,想让您了解它的最后一部分。

        6
  •  0
  •   Roland Schneider    17 年前

    日期和日历的主要区别在于,该日期只是一个值对象,没有修改它的方法。所以它是为在某处存储日期/时间信息而设计的。如果使用日历对象,则可以在将其设置为持久性实体(该实体使用日期/时间信息执行某些业务逻辑)后对其进行修改。这是非常危险的,因为实体无法识别这种变化。 calendar类是为日期/时间上的操作而设计的,比如添加日期或类似的内容。

    拿着你的例子玩我得到了以下信息:

    import java.text.DateFormat;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    
    public class TimeZoneExtracter {
    
        public static final void main(String[] args) throws ParseException {
            DateFormat dbFormatter = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz");
            System.out.println(dbFormatter.getTimeZone());
            dbFormatter.parse("Fr, September 26, 2008 8:30 PM Eastern Daylight Time");
            System.out.println(dbFormatter.getTimeZone());
        }
    
    }
    

    输出:

    sun.util.calendar.zoneinfo[id=“欧洲/柏林”… sun.util.calendar.zoneinfo[id=“非洲/亚的斯亚贝巴”…

    这是你想要的结果吗?

        7
  •  0
  •   Mike Pone    17 年前

    艾德说得对。您希望在分析时间之后在DateFormat对象上设置时区。

     String rawDate = "Friday, September 26, 2008 8:30 PM Eastern Daylight Time";
     DateFormat dbFormatter = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz");
     Date scheduledDate = dbFormatter.parse(rawDate);
    
     System.out.println(rawDate); 
     System.out.println(scheduledDate); 
     System.out.println(dbFormatter.getTimeZone().getDisplayName());
    

    生产

    Friday, September 26, 2008 8:30 PM Eastern Daylight Time
    Fri Sep 26 20:30:00 CDT 2008
    Eastern Standard Time
    
    推荐文章