简体   繁体   English

为什么Java从系统中读取其默认设置

[英]Why does Java read its default settings from the system

Java is reading the locale, timezone and encoding information (and perhaps more) from the system it is installed on. Java正在从安装它的系统中读取区域设置,时区和编码信息(可能还有更多信息)。

This often brings bad surprises (brought me one just yesterday). 这往往带来不好的惊喜(昨天就给我带来了一个)。 Say your development and production servers are set to have TimeZone GMT+2. 假设您的开发和生产服务器设置为TimeZone GMT + 2。 Then you deploy on a production server set to GMT. 然后在生产服务器上部署设置为GMT。 a 2-hour shift may not be easy to observe immediately. 2小时的班次可能不容易立即观察。 And although you can pass a TimeZone to your calendars, APIs might be instantiating calendars (or dates) using the default timezone. 虽然您可以将TimeZone传递给日历,但API可能会使用默认时区实例化日历(或日期)。

Now, I know one should be careful with these settings, but are easy to miss , hence make programs more error-prone. 现在,我知道应该小心这些设置,但很容易错过 ,因此使程序更容易出错。

So, why doesn't Java have its own defaults - UTF-8, GMT, en_US (yes, I'm on non-en_US locale, but having it as default is fine). 那么,为什么Java没有自己的默认值 - UTF-8,GMT,en_US(是的,我在非en_US语言环境中,但是将其作为默认设置就可以了)。 Applications could read the system settings via some API, if needed. 如果需要,应用程序可以通过某些API读取系统设置。

Thus programs would be more predictable. 因此,计划将更具可预测性。

So, what is the reason behind this decision? 那么,这个决定背后的原因是什么?

This isn't unique to Java. 这不是Java独有的。 Many systems default to the system time zone. 许多系统默认为系统时区。 After all, what else can they do? 毕竟,他们还能做些什么呢?

Time zones are a thorny issues, particularly when the application needs to deal with several time zones. 时区是一个棘手的问题,特别是当应用程序需要处理多个时区时。 That's why sites such as this one put everything in UTC. 这就是为什么像这样的网站将所有内容都放在UTC中。

As for your situation, it's hard to comment because the description is rather vague but it sounds like this is your error. 至于你的情况,很难评论,因为描述相当模糊,但听起来这是你的错误。 If you save a date (without time zone) in one place at GMT+2 and then load it another at GMT then you've done something wrong. 如果您在GMT + 2的某个地方保存一个日期(没有时区),然后在GMT加载另一个,那么您做错了。

I don't see why having an extra set of defaults would make this easier. 我不明白为什么有一组额外的默认值会使这更容易。 Surely those defaults would still have to be read from somewhere - so they'd presumably default from the operating system. 当然,这些默认值仍然必须从某个地方读取 - 因此它们可能默认来自操作系统。

If you want to influence the defaults, there are usually system properties you can set when you launch your app, eg 如果要影响默认值,通常可以在启动应用程序时设置系统属性,例如:

java -Duser.timezone=Europe/London

etc. 等等

Personally I think the problem isn't with the choice of default - it's the fact that it's used so easily. 就个人而言,我认为问题不在于默认选择 - 事实上它很容易使用。 Even Joda Time (which I love in many, many respects) makes it too easy to accidentally use the default time zone. 即使是Joda Time(我喜欢很多很多方面)也很容易意外地使用默认时区。 The same is true with encodings etc. 编码等也是如此。

EDIT: Another option is to use a main method (or other early-initialization module) which calls 编辑:另一种选择是使用调用的main方法(或其他早期初始化模块)

TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));

and likewise for other system-specific defaults. 同样适用于其他系统特定的默认值。

I reckon it's because it is less surprising for more people. 我认为这是因为对更多人而言,这并不令人惊讶。

Most programs (including those in other languages) use the timezone of the local deployment. 大多数程序(包括其他语言的程序)使用本地部署的时区。 That's been the case for ages. 多年来一直如此。 If you want something else, you can override it. 如果你想要别的东西,你可以覆盖它。 Imagine if it was the other way: we'd have the same question in the reverse direction but asked by more people. 想象一下,如果是另一种方式:我们在相反的方向上有相同的问题,但更多的人会问。

(Use UTC for timestamps where you can't just have offset-from-epoch.) (使用UTC作为时间戳,你不能只有偏​​离历元的时间。)

I can imagine this need whenever you develop an enterprise (web) application running on a server which is to be accessed by everyone at the world, but this is not needed for normal desktop applications. 每当您开发在服务器上运行的企业(Web)应用程序时,我都可以想象这种需求,该应用程序将由世界上的每个人访问,但普通桌面应用程序不需要这样做。 Try to think in their context as well. 尝试在他们的背景下思考。 You don't want to have programming-unaware client application users to configure their default system settings only because Java has its own defaults. 您不希望让编程不知道的客户端应用程序用户仅配置其默认系统设置,因为Java有自己的默认设置。 You as an enterprise (web) application developer truly has to take those things into account yourself. 作为企业(Web)应用程序开发人员,您必须自己考虑这些因素。

If you deploy things on a production server set to GMT, the sensible default behavior is to use GMT as the default. 如果在设置为GMT的生产服务器上部署内容,则合理的默认行为是使用GMT作为默认值。 Java is supposed to be a programming language and framework, not a whole operating-system-within-a-system.. Maintaining its own set of default settings is not part of a standard library's job. Java应该是一种编程语言和框架,而不是整个系统内的操作系统。维护它自己的一组默认设置不是标准库工作的一部分。

And consider the alternate situation: if Java did maintain its own settings for things like time zones, everyone who wanted to use different settings (eg everyone not in GMT, probably ~90% of computer users) who wanted to use a Java program would have to manually change Java's time zone. 并考虑另一种情况:如果Java确实为时区等事情保留了自己的设置,那么想要使用不同设置的每个人(例如,不是GMT的人,可能是约90%的计算机用户)都希望使用Java程序手动更改Java的时区。 It would be even more complicated for people who use systems which combine Java with some other language, because you'd have different programs on the same computer using different (and probably incompatible) settings. 对于使用将Java与其他语言结合在一起的系统的人来说会更复杂,因为在同一台计算机上使用不同(可能不兼容)的设置会有不同的程序。

tl;dr TL;博士

“Why” is irrelevant, as frameworks and APIs providing such defaults is all-to-common. “为什么”是无关紧要的,因为提供此类默认值的框架和API是通用的。

Always pass a ZoneId & Locale explicitly, even if optional. 始终显式传递ZoneIdLocale ,即使是可选的。

LocalDate.now( ZoneId.of( "Africa/Tunis" ) )

…and… …和…

DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL )
    .withLocale( Locale.JAPAN )

Specify optional arguments 指定可选参数

Not only is the JVM's current default time zone and locale outside your control as a programmer (coming from host OS or from JVM launch parameters), they can change at any moment during runtime. 作为程序员(来自主机操作系统或来自JVM启动参数),JVM当前的默认时区和区域设置不仅在您的控件之外,它们可以运行时随时更改。 Any code in any thread of any app within the JVM can change either the default zone or locale. JVM中任何应用程序的任何线程中的任何代码都可以更改默认区域或区域设置。

Better to always specify explicitly the desired/expected zone or locale by passing optional arguments, rather than rely implicitly on the JVM's current default. 最好总是通过传递可选参数明确指定所需/期望的区域或区域设置 ,而不是隐式依赖于JVM的当前默认值。

Time zone 时区

A time zone is crucial in determining a date. 时区对于确定日期至关重要。 For any given moment, the date varies around the globe by zone. 对于任何给定的时刻,日期在全球范围内因地区而异。 For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec . 例如, 法国巴黎午夜过后几分钟是新的一天,而在魁北克蒙特利尔仍然是“昨天”。

If no time zone is specified, the JVM implicitly applies its current default time zone. 如果未指定时区,则JVM会隐式应用其当前的默认时区。 That default may change at any moment, so your results may vary. 该默认值可能随时更改,因此您的结果可能会有所不同。 Better to specify your desired/expected time zone explicitly as an argument. 最好明确指定您期望/预期的时区作为参数。

Specify a proper time zone name in the format of continent/region , such as America/Montreal , Africa/Casablanca , or Pacific/Auckland . continent/region的格式指定适当的时区名称 ,例如America/MontrealAfrica/CasablancaPacific/Auckland Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!). 切勿使用3-4字母缩写,例如ESTIST因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;

If you want to use the JVM's current default time zone, ask for it and pass as an argument. 如果要使用JVM的当前默认时区,请求它并作为参数传递。 If omitted, the JVM's current default is applied implicitly. 如果省略,则隐式应用JVM的当前默认值。 Better to be explicit, as the default may be changed at any moment during runtime by any code in any thread of any app within the JVM. 最好是显式的,因为默认情况下可以在运行期间随时由JVM中任何应用程序的任何线程中的任何代码更改。

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

Locale 语言环境

The DateTimeFormatter class can automatically localize when generating a String representing a date-time value. 在生成表示日期时间值的String时, DateTimeFormatter类可以自动本地化。

Instant instant = Instant.now();  // Current moment in UTC with a resolution of up to nanoseconds.
ZoneId z = ZoneId.of( "America/Montreal" ); 
ZonedDateTime zdt = instant.atZone( z );  // Adjust from UTC to a specific time zone. Same moment, different wall-clock time.

To localize, specify: 要进行本地化,请指定:

  • FormatStyle to determine how long or abbreviated should the string be. FormatStyle用于确定字符串的长度或缩写。
  • Locale to determine (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, separators, and such. 用于确定(a)翻译日期名称,月份名称等的人类语言的Locale ,以及(b)决定缩写,大小写,标点符号,分隔符等问题的文化规范。

Example: 例:

ZoneId z = ZoneId.of( "Pacific/Auckland" ); 
ZonedDateTime zdt = ZonedDateTime.now( z ) ;

Locale l = Locale.CANADA_FRENCH ; 
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( l );
String output = zdt.format( f );

Notes 笔记

By the way, note that in date-time handling, the issues of time zone and locale are distinct, orthogonal. 顺便说一下,请注意在日期时间处理中,时区和区域设置的问题是不同的,正交的。 The first defines the meaning or content of the date-time value, the second controls its formatting for display. 第一个定义日期时间值的含义或内容,第二个控制其格式以供显示。 You can have a Québec moment display in Japanese format, or an India moment display in Norwegian format. 您可以使用日语格式的魁北克时刻显示,或以挪威语格式显示印度时刻。

Say your development and production servers are set to have TimeZone GMT+2. 假设您的开发和生产服务器设置为TimeZone GMT + 2。

Generally speaking, servers should be set to UTC. 一般来说,服务器应设置为UTC。 But as discussed above, never rely on that. 但如上所述,永远不要依赖于此。 Pass your desired/expected time zone as arguments, even if your desire is UTC. 将您期望/预期的时区作为参数传递,即使您的愿望是UTC。

a 2-hour shift may not be easy to observe immediately. 2小时的班次可能不容易立即观察。

You can now do testing more easily with java.time by passing alternate implementations of Clock class. 现在,您可以通过传递Clock类的备用实现来更轻松地使用java.time进行测试。 That class itself provides alternate behaviors such as setting a fixed time, or setting the clock to be so many hours/minutes ahead or behind of true time. 该类本身提供了替代行为,例如设置固定时间,或将时钟设置为真实时间前后数小时/分钟。

You will likely need to rewrite some code to communicate the zone, locale, or encoding via some sort of dependency-injection . 您可能需要重写一些代码以通过某种依赖注入来传达区域,区域设置或编码。 That might be as simple as passing arguments to a section of code. 这可能就像将参数传递给代码段一样简单。

And although you can pass a TimeZone to your calendars, APIs might be instantiating calendars (or dates) using the default timezone. 虽然您可以将TimeZone传递给日历,但API可能会使用默认时区实例化日历(或日期)。

Seems to be a very common problem that programmers ignore the issue of time zone and locale. 似乎是程序员忽略时区和语言环境问题的一个非常普遍的问题。 Probably due more often to ignorance than laziness. 可能更多的是因为无知而不是懒惰。

No magic bullet here except to: 这里没有灵丹妙药除了:

  • Educate your programmers about date-time handling, localizing, and character encoding . 向您的程序员介绍日期时间处理,本地化和字符编码
  • Set a standard for your team insisting that zone, locale, and character-encoding always be explicit. 为您的团队设置标准,坚持区域,区域设置和字符编码始终是明确的。 If the default is desired, make an explicit call to get the default. 如果需要默认值,请进行显式调用以获取默认值。

I do agree with the sentiment behind your Question. 我同意你的问题背后的情绪。 Frameworks and APIs should never provide default values for time zone, locale, and character-encoding , in my humble opinion. 在我看来, 框架和API永远不应该为时区,区域设置和字符编码提供默认值 Relying on such defaults without thinking by the programmers is a source of some of the most troubling elusive runtime bugs. 在没有程序员思考的情况下依赖这样的默认值是一些最令人难以捉摸的难以捉摸的运行时错误的根源。 But, c'est la vie , we have to deal with reality as-is. 但是, 这就是生活 ,我们必须面对现实原样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从Java应用程序读取的文件是否会调用系统调用? - Does a file read from a Java application invoke a system call? Spring Boot 在哪里存储其默认日志记录设置 - Where does Spring Boot store its default logging settings 如何从Java中的系统设置获取代理设置 - How to get proxy settings from system settings in Java 为什么 java/sql 模块默认不从自动模块解析,还有其他系统模块默认不解析 - why is java/sql module not resolved by default from an automatic module and are there other system modules which are not resolved by default 从gae java文件中读取设置 - read settings from a file in gae java 为什么Android有自己的URI实现并且不使用默认的Java实现? - Why does Android have its own URI implementation and doesn't use the default Java implementation? 为什么getCurrentInterruptionFilter BroadcastReceiver可以通过“快速设置”而不是“设置”工作? - Why does getCurrentInterruptionFilter BroadcastReceiver work from Quick Settings but not from Settings? Java如何使用系统代理设置访问网站 - How does Java use system proxy settings to access a website 为什么Java从套接字读取随机数量而不从整个消息读取随机数量? - Why does Java read random amounts from a socket but not the whole message? 为什么 TRANSACTION_READ_COMMITTED 是 Java 中的默认值? - Why is TRANSACTION_READ_COMMITTED the default in Java?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM