Blackberry date time string formatting

2019-02-20 18:46发布

问题:

I need to parse the date/time string, to add the raw offset and convert it according to local time zone.

The date time that I get from server is in this format : "05-25-2012 02:30 PM"

This format is not parsed by : HttpDateParser.parse(time) method

But HttpDateParser does parse this format : "25-MAY-2012 02:30 PM"

Can you tell me, how should I parse "05-25-2012 02:30 PM" String in BB to get a long value.

I have 1 more problem, I need to display time zone in format GMT, IST, but all I can display is Asia/Calcutta, America/Los_Angeles and so..

回答1:

BlackBerry Java is missing some useful String handling and Date formatting APIs that developers are used to in Desktop Java, or even Android Java applications. So, you have to do some of the parsing yourself, and it's a pain if you need to handle time zones. You didn't say what time zone your server is in, so I have to assume that you know that, even though the string you show in your question doesn't have time zone information.

Disclaimer: this code does not come straight out of one of my apps, so it has not been through rigorous testing. It is a proof of concept. You'll have to test all your own time zones, and probably verify that it works during daylight savings time changeovers. Also, see the blackberry API docs for information about limitations of the TimeZone.getOffset() method I use here.

First my imports:

import java.util.Date;
import java.util.TimeZone;
import java.util.Hashtable;
import java.util.Calendar;

import net.rim.device.api.i18n.SimpleDateFormat;
import net.rim.device.api.io.http.HttpDateParser;
import net.rim.device.api.util.StringUtilities;

Then, the code to parse the string given by the server. I assume that this time is either in the server's current time zone, adjusted for daylight savings, or in some other known time zone that may not be the mobile client's time zone. Change my value, New_York, for the known server time zone to suit your needs:

   private Date parseServerTime(String timeFromServer) {
      // separate the time string into tokens, which accepts ' ' or '-' or ':' as delimeters
      String tokens[] = StringUtilities.stringToKeywords(timeFromServer);
      int month = Integer.parseInt(tokens[0]);
      int day = Integer.parseInt(tokens[1]);
      int year = Integer.parseInt(tokens[2]);
      int hours = Integer.parseInt(tokens[3]);
      int minutes = Integer.parseInt(tokens[4]);
      boolean isPm = tokens[5].equalsIgnoreCase("PM");
      // convert hours to 24 hour time
      if (hours == 12 && !isPm) {
         hours = 0;
      } else if (hours != 12 && isPm) {
         hours += 12;
      }
      int millisToday = ((hours * 60) + minutes) * 60 * 1000;

      StringBuffer reformattedTime = new StringBuffer();
      // reorder the year, month and day to be able to use HttpDateParser (YYYY-MM-DDTHH:mm)
      reformattedTime.append(tokens[2]).append('-').append(tokens[0]).append('-').append(tokens[1]);
      reformattedTime.append('T').append(hours).append(':').append(minutes);
      long unadjustedTimeFromServer = HttpDateParser.parse(reformattedTime.toString());

      int monthIndex = month - 1;
      // This example assumes the server is giving us a time from the Eastern US time zone
      TimeZone serverZone = TimeZone.getTimeZone("America/New_York");
      int serverOffset = serverZone.getOffset(1, // 1 -> AD, not BC
            year, 
            monthIndex, 
            day, 
            1, // I'm not sure, but I don't think day-of-week matters here?
            millisToday);

      return new Date(unadjustedTimeFromServer - serverOffset);
   }

Then, I format the parsed Date for the client, using their device's time zone, and the short code you want for time zone display:

   private String formatClientTime(Date dateFromServer) {
      TimeZone clientZone = TimeZone.getDefault();
      String tzKey = clientZone.toString();
      String[] tzDisplayNames = StringUtilities.stringToKeywords((String) _timeZones.get(tzKey));

      // we might have to use the "daylight" time zone short code
      Calendar cal = Calendar.getInstance(clientZone);
      cal.setTime(dateFromServer);
      int clientOffset = clientZone.getOffset(1, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
            cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_WEEK), cal.get(Calendar.MILLISECOND));
      int rawOffset = clientZone.getRawOffset();

      // if the daylight savings time adjusted offset isn't equal to the raw offset, we
      //   must be in daylight savings time
      boolean isTimeDuringDaylightSavings = (clientOffset != rawOffset);
      String tzCode = isTimeDuringDaylightSavings ? tzDisplayNames[1] : tzDisplayNames[0];

      // TODO: change this to whatever output format you want to use for the UI
      SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy hh:mm aa");
      return formatter.formatLocal(dateFromServer.getTime()) + " " + tzCode;
   }

And I use all this code like so:

  mapTimeZoneCodes(); 

  Date date = parseServerTime("05-25-2012 02:30 PM");
  String text = formatClientTime(date);

My mapTimeZoneCodes() method is just a utility to initialize a mapping between the long BlackBerry time zone strings that you don't like ("Asia/Calcutta") and the short codes ("IST"). As far as I know, BlackBerry provides no API to display the short codes that people are used to, at least for OS 5.0, which many developers still need to support. You might choose to refactor this into a static utility class. Here is the mapping I used, based on this article on Desktop Java.

I only bothered to fill in a few of the time zone string mappings, to test this out. If you want to use this, you'll need to fill in the rest, or at least the ones your app needs, or it will probably crash. Notice that the table I use needs two (sub)strings for each time zone, for daylight savings. If you feel like it, you could update the solution when you finish the work. But, I'll leave that to you.

   private Hashtable _timeZones;

   private void mapTimeZoneCodes() {
      // TODO: you can uncomment this code and use it to generate your map of time zone ids and short codes
      //String[] ids = TimeZone.getAvailableIDs();
      //for (int i = 0; i < ids.length; i++) {
      //   System.out.println(" _timeZones.put(\"" + ids[i] + "\", \"\");");
      //}
      _timeZones = new Hashtable();
      _timeZones.put("Pacific/Kwajalein", "");
      _timeZones.put("Pacific/Midway", "");
      _timeZones.put("Pacific/Honolulu", "");
      _timeZones.put("America/Anchorage", "");
      _timeZones.put("America/Tijuana", "");
      _timeZones.put("America/Los_Angeles", "PST PDT");
      _timeZones.put("America/Phoenix", "");
      _timeZones.put("America/Denver", "MST MDT");
      _timeZones.put("America/Tegucigalpa", "");
      _timeZones.put("America/Tegucigalpa_2", "");
      _timeZones.put("America/El_Salvador", "");
      _timeZones.put("America/Regina", "");
      _timeZones.put("America/Chicago", "CST CDT");
      _timeZones.put("America/Mexico_City", "");
      _timeZones.put("America/Mexico_City_2", "");
      _timeZones.put("America/Bogota", "");
      _timeZones.put("America/Indianapolis", "");
      _timeZones.put("America/New_York", "EST EDT");
      _timeZones.put("America/Caracas", "");
      _timeZones.put("America/La_Paz", "");
      _timeZones.put("America/Manaus", "");
      _timeZones.put("America/Santiago", "");
      _timeZones.put("America/Halifax", "");
      _timeZones.put("America/St_Johns", "");
      _timeZones.put("America/Montevideo", "");
      _timeZones.put("America/Guyana", "");
      _timeZones.put("America/Buenos_Aires", "");
      _timeZones.put("America/Sao_Paulo", "");
      _timeZones.put("America/Godthab", "");
      _timeZones.put("America/South_Georgia", "");
      _timeZones.put("Atlantic/Cape_Verde", "");
      _timeZones.put("Atlantic/Azores", "");
      _timeZones.put("GMT", "GMT");
      _timeZones.put("Europe/Dublin", "");
      _timeZones.put("Africa/Luanda", "");
      _timeZones.put("Europe/Amsterdam", "");
      _timeZones.put("Europe/Belgrade", "");
      _timeZones.put("Europe/Brussels", "");
      _timeZones.put("Europe/Belgrade Yugoslavia(YU)", "");
      _timeZones.put("Africa/Windhoek", "");
      _timeZones.put("Asia/Amman", "");
      _timeZones.put("Africa/Harare", "");
      _timeZones.put("Asia/Jerusalem", "");
      _timeZones.put("Europe/Minsk", "");
      _timeZones.put("Africa/Cairo", "");
      _timeZones.put("Asia/Beirut", "");
      _timeZones.put("Europe/Athens", "");
      _timeZones.put("Europe/Helsinki", "");
      _timeZones.put("Asia/Kuwait", "");
      _timeZones.put("Africa/Nairobi", "");
      _timeZones.put("Asia/Baghdad", "");
      _timeZones.put("Europe/Moscow", "");
      _timeZones.put("Asia/Tehran", "");
      _timeZones.put("Asia/Tbilisi", "");
      _timeZones.put("Asia/Muscat", "");
      _timeZones.put("Asia/Baku", "");
      _timeZones.put("Asia/Yerevan", "");
      _timeZones.put("Asia/Caucasus", "");
      _timeZones.put("Asia/Kabul", "");
      _timeZones.put("Asia/Karachi", "");
      _timeZones.put("Asia/Tashkent", "");
      _timeZones.put("Asia/Yekaterinburg", "");
      _timeZones.put("Asia/Calcutta", "");
      _timeZones.put("Asia/Colombo", "");
      _timeZones.put("Asia/Katmandu", "");
      _timeZones.put("Asia/Dhaka", "");
      _timeZones.put("Asia/Almaty", "");
      _timeZones.put("Asia/Rangoon", "");
      _timeZones.put("Asia/Bangkok", "");
      _timeZones.put("Asia/Krasnoyarsk", "");
      _timeZones.put("Asia/Hong_Kong", "");
      _timeZones.put("Asia/Kuala_Lumpur", "");
      _timeZones.put("Australia/Perth", "");
      _timeZones.put("Asia/Taipei", "");
      _timeZones.put("Asia/Irkutsk", "");
      _timeZones.put("Asia/Tokyo", "");
      _timeZones.put("Asia/Seoul", "");
      _timeZones.put("Asia/Yakutsk", "");
      _timeZones.put("Australia/Darwin", "");
      _timeZones.put("Australia/Adelaide", "");
      _timeZones.put("Pacific/Guam", "");
      _timeZones.put("Asia/Vladivostok", "");
      _timeZones.put("Australia/Hobart", "");
      _timeZones.put("Australia/Brisbane", "");
      _timeZones.put("Australia/Sydney", "");
      _timeZones.put("Asia/Magadan", "");
      _timeZones.put("Pacific/Fiji", "");
      _timeZones.put("Pacific/Auckland", "");
      _timeZones.put("Pacific/Tongatapu", "");
   }