日期转换为其他区域设置

时间:2016-09-07 08:38:04

标签: java android date locale

我正在开展一个Android项目,我正在实施本地化。

我将获得区域设置和时区。使用这些信息,我写了下面的代码:

String []locale= User.getInstance().getLanguage().split("-");//Assume, locale[0]=hi, locale[1]=IN
Calendar choosenDate = Calendar.getInstance(new Locale(locale[0],locale[1]));
SimpleDateFormat Dformat = new SimpleDateFormat("MMMM dd yyyy",new Locale(locale[0],locale[1]));
Log.d("MY_APP","***********Newly converted date:"+Dformat.format(choosenDate.getTime()));

我从上面的代码中得到的日志是:

**********Newly converted date:सितंबर 07 2016

所以,基本上我面临的问题只是"MMMM",即:月份部分被转换为指定的区域设置(在上面的语言中它是印地语(hi-IN))。但是,"dd yyyy"未转换为印地语。

有人能告诉我我做错了什么,或者我怎样才能确保即使是dd和yyyy部分也会转换为指定的语言环境。

3 个答案:

答案 0 :(得分:2)

看起来很有效:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello World!");
        String []locale = {"hi", "IN"};
        Calendar choosenDate = Calendar.getInstance(new Locale(locale[0],locale[1]));
        SimpleDateFormat Dformat = new SimpleDateFormat("MMMM dd yyyy",new Locale(locale[0],locale[1]));
        System.out.println("MY_APP***********Newly converted date:"+ Dformat.format(choosenDate.getTime() ));
    }
}

测试:

/usr/lib/jvm/java-1.8.0-openjdk-amd64/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:32790,suspend=y,server=n -Dfile.encoding=UTF-8 -classpath /usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/charsets.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/cldrdata.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/dnsns.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/icedtea-sound.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/jaccess.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/localedata.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/nashorn.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/sunec.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/sunjce_provider.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/sunpkcs11.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/zipfs.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/jce.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/jsse.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/management-agent.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/resources.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/rt.jar:/home/dac/proj/javatest2016/out/production/javatest2016:/home/dac/Downloads/idea-IU-145.972.3/lib/idea_rt.jar Main
Connected to the target VM, address: '127.0.0.1:32790', transport: 'socket'
Hello World!
MY_APP***********Newly converted date:सितंबर ०७ २०१६
Disconnected from the target VM, address: '127.0.0.1:32790', transport: 'socket'

Process finished with exit code 0

您可以尝试使用该计划online

答案 1 :(得分:2)

阿拉伯语与印度教风格的数字

显然您希望将数字从阿拉伯风格转换为印度风格,如此Wikipedia article on Arabic-Hindu numerals所示。 (不是我知道关于这个主题的任何。请原谅在这里使用任何语言/国家/传统术语的不当。)

Image of variations on the Arabic-Hindu numerals (sourced from Wikipedia)

你的问题并没有明显表明你是在追求数字数字的替代方式;发布到Stack Overflow时请更加小心。

Oracle Java 8上的阿拉伯风格

仅供参考,我使用现代java.time类运行以下代码,而不是问题中使用的麻烦的遗留日期时间类。我只得到阿拉伯风格的数字。

我遍历任意Locale个对象的集合。对于每个I循环遍历所有四个FormatStyle对象,以指定用于自动本地化当前时刻输出的缩写长度。

ZoneId z = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.now ( z );

List<Locale> locales = new ArrayList<> ();
locales.add ( Locale.US );
locales.add ( Locale.CANADA_FRENCH );
locales.add ( Locale.TAIWAN );
locales.add ( new Locale ( "hi" , "IN" ) );  // Hindi, India.
// locales.add ( new Locale ( "ar" , "MA" ) );  // Arabic, Morocco

EnumSet<FormatStyle> formatStyles = EnumSet.allOf ( FormatStyle.class );

for ( Locale locale : locales ) {
    System.out.println ( "—————" );
    System.out.println ( "Locale: " + locale );
    for ( FormatStyle formatStyle : formatStyles ) {
        DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime ( formatStyle ).withLocale ( locale );
        System.out.println ( String.format ( "%1$-" + 20 + "s" , "FormatStyle: " + formatStyle ) + "  →  " + zdt.format ( f ) );
    }
}
System.out.println ( "—————" );

在macOS上运行Java SE 8 Update 102的Oracle实现时。

—————
Locale: en_US
FormatStyle: FULL     →  Wednesday, September 7, 2016 6:46:00 PM EDT
FormatStyle: LONG     →  September 7, 2016 6:46:00 PM EDT
FormatStyle: MEDIUM   →  Sep 7, 2016 6:46:00 PM
FormatStyle: SHORT    →  9/7/16 6:46 PM
—————
Locale: fr_CA
FormatStyle: FULL     →  mercredi 7 septembre 2016 18 h 46 EDT
FormatStyle: LONG     →  7 septembre 2016 18:46:00 EDT
FormatStyle: MEDIUM   →  2016-09-07 18:46:00
FormatStyle: SHORT    →  16-09-07 18:46
—————
Locale: zh_TW
FormatStyle: FULL     →  2016年9月7日 星期三 下午06時46分00秒 EDT
FormatStyle: LONG     →  2016年9月7日 下午06時46分00秒
FormatStyle: MEDIUM   →  2016/9/7 下午 06:46:00
FormatStyle: SHORT    →  2016/9/7 下午 6:46
—————
Locale: hi_IN
FormatStyle: FULL     →  बुधवार, 7 सितंबर, 2016 6:46:00 अपराह्न EDT
FormatStyle: LONG     →  7 सितंबर, 2016 6:46:00 अपराह्न EDT
FormatStyle: MEDIUM   →  7 सितंबर, 2016 6:46:00 अपराह्न
FormatStyle: SHORT    →  7/9/16 6:46 अपराह्न
—————

之谜:传统类的执行方式与java.time类

不同

奇怪的是,当我使用问题中的确切源代码时,我也得到与the Answer by Dac Saunders Hindu/Indian-style numerals中看到的输出相同的输出。

所以我简化了代码。当实际上正在格式化java.util.Calendar对象时,该源代码实际上是在实例化java.util.Date对象。所以我完全删除了Calendar

Locale l = new Locale ( "hi" , "IN" );

// java.time
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "MMMM dd uuuu" ).withLocale ( l );
System.out.println ( ZonedDateTime.now ().format ( f ) );

// Legacy date-time classes.
SimpleDateFormat dFormat = new SimpleDateFormat ( "MMMM dd yyyy" , l );
System.out.println ( dFormat.format ( new java.util.Date () ) );
  

सितंबर07 2016

     

सितंबर07 2016

虽然我不完全理解这种行为,但似乎我们可以根据Zax的Android行为,Dac Saunders的Ubuntu Linux体验以及我在macOS上的经验得出两个结论:

  • 旧版日期时间类的Android实现与Linux&amp;苹果系统。在Android中,阿拉伯风格的数字在Linux / macOS上我们得到了印度风格。
  • java.time类只提供阿拉伯风格的数字,行为与他们取代印度风格的遗留类别不同。也许应该提交错误报告。

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧日期时间类,例如java.util.Date.Calendar和&amp; java.text.SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。

大部分java.time功能都被反向移植到Java 6&amp; ThreeTen-Backport中的7,并进一步适应Android中的ThreeTenABP(见How to use…)。

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuarter等。

答案 2 :(得分:2)

为什么格式化程序有时会使用阿拉伯语,有时使用印度语数字?

SimpleDateFormatDateTimeFormatter(在Java 8上)后面的格式引擎使用最初基于Common Locale Date Repository (CLDR)The Unicode Consortium数据的本地化资源。在旧的CLDR数据(例如v17)中,我们发现了印地语(iso-639-code hi)的默认编号系统:

<defaultNumberingSystem>deva</defaultNumberingSystem>

但是最新的CLDR-version v29 shows

<defaultNumberingSystem>latn</defaultNumberingSystem>

CLDR代码字&#34; deva&#34;和&#34; latn&#34;表示印度数字(从代码点0x966开始)。阿拉伯数字0-9。因此,Java或Android平台的行为取决于版本。旧版本的平台使用旧数据,而较新版本使用更新的CLDR数据。 对于手机来说,很难甚至无法预测Android会真正使用哪些数据。并非每个用户都会用来更新Android版本,有时制造商也会操纵资源。

是否可以配置格式化程序使用的数字系统?

YES!我展示了三种方式。

a) java.text.SimpleDateFormat

Locale hindi = new Locale("hi", "IN");

DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(hindi);
char required = '०'; // copied from your comment
DecimalFormat numberFormat = new DecimalFormat();
dfs.setZeroDigit(required); // or any other zero digit like '0'
numberFormat.setDecimalFormatSymbols(dfs);

SimpleDateFormat sdf = new SimpleDateFormat("MMMM dd yyyy", hindi);
sdf.setNumberFormat(numberFormat);
System.out.println("SimpleDateFormat: " + sdf.format(new Date())); // सितंबर २३ २०१६

b) java.time.format.DateTimeFormatter (在Android上,您可以使用ThreetenABP代替)

Locale hindi = new Locale("hi", "IN");

char required = '०'; // copied from your comment
DecimalStyle style = DecimalStyle.of(hindi).withZeroDigit(required);

DateTimeFormatter dtf =
    DateTimeFormatter.ofPattern("MMMM dd yyyy", hindi).withDecimalStyle(style);
System.out.println("java.time: " + LocalDate.now().format(dtf)); // सितंबर २३ २०१६

注意:此解决方案仍然使用Android平台的资源(例如在Android中查找月份名称)。

c)我的图书馆 Time4A (管理自己独立的i18n资源)

Locale hindi = new Locale("hi", "IN");

ChronoFormatter<PlainDate> cf =
    ChronoFormatter.ofDatePattern("MMMM dd yyyy", PatternType.CLDR, hindi).with(
        Attributes.NUMBER_SYSTEM,
        NumberSystem.DEVANAGARI
    );
System.out.println("Time4A: " + cf.format(PlainDate.nowInSystemTime())); // सितंबर २३ २०१६