Ken*_*Kin 6 c# java timezone jodatime nodatime
由于某些游戏开发可能会使用过去或未来的日期时间,以及日期时间模拟的任何时区,即使我们从未实际接触过它们.对于这个假设,并不是说我在计算假date time的,而是在任何时区的任何日期时间计算的正确性,就像它实际上一样.
我之前曾问过一个关于中国在Java中的时区问题的问题,这被认为是一个重复的问题,我就删除了它.但是,从这个评论主题中,我知道它是Java中的某种时间倒带(转换?)问题,而不仅仅是时区变化.
现在,我以不同的方式重新发布此问题,以便通过以下方式提出此问题:
Java中的代码
import org.joda.time.*;
import java.util.*;
class PandaTest {
static long Subtract(
Date minuend, Date subtrahend, DateTimeZone zone) {
long millis;
if(null==zone)
millis=minuend.getTime()-subtrahend.getTime();
else {
long rhs=
(new LocalDateTime(subtrahend)).toDateTime(zone)
.getMillis();
long lhs=
(new LocalDateTime(minuend)).toDateTime(zone)
.getMillis();
millis=lhs-rhs;
}
return millis/1000;
}
static Date MakeTime(
int year, int month, int day, int hour, int minute, int second
) {
Calendar calendar=
Calendar.getInstance(TimeZone.getTimeZone("PRC"));
calendar.set(year, month-1, day, hour, minute, second);
return calendar.getTime();
}
static void puts(String arg0) {
System.out.println(arg0);
}
static void ShowDuration(DateTimeZone zone, Date ... args) {
int argc=args.length;
puts("--- ");
puts("Time Zone: "+(null!=zone?zone.toString():"unspecified"));
for(int i=0; argc-->0; ++i) {
puts("Time "+i+": "+args[i]);
if(i>0) {
long duration=Subtract(args[i], args[i-1], zone);
puts("Duration = "+duration);
}
}
}
public static void main(String[] args) {
Date retainsOfTheDay=MakeTime(1900, 1, 1, 8, 5, 51+0);
Date somewhereInTime=MakeTime(1900, 1, 1, 8, 5, 51+1);
DateTimeZone zone=DateTimeZone.forID("PRC");
ShowDuration(null, retainsOfTheDay, somewhereInTime);
ShowDuration(zone, retainsOfTheDay, somewhereInTime);
}
}
Run Code Online (Sandbox Code Playgroud)如果我LocalDateTime从DateJava 构建一个JodaTime,就会出现问题.JDK的版本是7u17,JodaTime是2.2.在NodaTime的C#中不会发生这种情况,我在这篇文章的后面添加了替代版本的代码以进行对比.
题
转换是如何发生的,它与Unix Epoch一样精确吗?
我可能以错误的方式使用术语转换.我的意思是减去的奇怪结果1900/1/1 8:5:52由1900/1/1 8:5:51Java编写的.那时没有时区变化.
这样的事情只发生在特定时区或所有时区(可能在某个不同时刻)吗?
如果一个人会在任意可能计算date timeS IN任何时区预计结果将永远是正确的,应该Date和Calendar使用?
如果是,如何在没有问题的情况下使用它们?
如果我们不再使用Date,并Calender在Java中,一旦我们可能在计算date time小号在1970年之前或在2038年之后?
替代准则
代码包含C#和Java中的内容,我们可以方便地对比C#和Java中的结果:
// Like Java, like Sharp ... the code contains content either in Java or C#
// An odd number of `slash-star-slash` at the beginning to compile in Java
// An even number of `slash-star-slash` at the beginning to compile in C#
// p.s.: zero would be treated as an even number
using Date=System.DateTime;
using NodaTime.TimeZones;
using NodaTime;
using System.Collections.Generic;
using System.Linq;
using System; /*/
import org.joda.time.*;
import java.util.*;
// ClockCant in Java
class ClockCant {
public static Date MakeTime(
int year, int month, int day, int hour, int minute, int second
) {
Calendar calendar=
Calendar.getInstance(TimeZone.getTimeZone("PRC"));
calendar.set(year, month-1, day, hour, minute, second);
return calendar.getTime();
}
public static DateTimeZone GetZoneFromId(String id) {
return DateTimeZone.forID(id);
}
public static String GetYourZoneId() {
return DateTimeZone.getDefault().getID();
}
public static long Subtract(
Date minuend, Date subtrahend, DateTimeZone zone) {
long millis;
if(null==zone)
millis=minuend.getTime()-subtrahend.getTime();
else {
long rhs=
(new LocalDateTime(subtrahend)).toDateTime(zone)
.getMillis();
long lhs=
(new LocalDateTime(minuend)).toDateTime(zone)
.getMillis();
millis=lhs-rhs;
}
return millis/1000;
}
}
// a minimum implementation of C#-like List<T> for Java
class List<T> {
public T[] ToArray() {
return _items;
}
public int Count() {
return _items.length;
}
public List(T ... args) {
_items=args;
}
T[] _items;
}
/*/// ClockCant in C#
class ClockCant {
public static Date MakeTime(
int year, int month, int day, int hour, int minute, int second) {
return new Date(year, month, day, hour, minute, second);
}
public static DateTimeZone GetZoneFromId(String id) {
return DateTimeZoneProviders.Tzdb[id];
}
public static String GetYourZoneId() {
return DateTimeZoneProviders.Tzdb.GetSystemDefault().Id;
}
public static long Subtract(
Date minuend, Date subtrahend, DateTimeZone zone) {
long ticks;
if(null==zone)
ticks=minuend.Subtract(subtrahend).Ticks;
else {
var rhs=
LocalDateTime.FromDateTime(subtrahend)
.InZoneLeniently(zone);
var lhs=
LocalDateTime.FromDateTime(minuend)
.InZoneLeniently(zone);
ticks=(lhs.ToInstant()-rhs.ToInstant()).Ticks;
}
return ticks/TimeSpan.TicksPerSecond;
}
}
// extension for Java-like methods in C#
static partial class JavaExtensions {
public static String toString(this Object x) {
return x.ToString();
}
}
class PandaTest { /*/ class PandaTest {
// in Java
public static void main(String[] args) {
Language="Java";
Main(args);
}
static void puts(String arg0) {
System.out.println(arg0);
}
static void ShowDuration(DateTimeZone zone, Date ... args) {
ShowDuration(zone, new List<Date>(args));
}
/*/// in C#
static void puts(String arg0) {
Console.WriteLine(arg0);
}
static void ShowDuration(DateTimeZone zone, params Date[] args) {
ShowDuration(zone, args.ToList());
}
/**/// the following code are for both C# and Java
static void ShowDuration(DateTimeZone zone, List<Date> args) {
int argc=args.Count();
Date[] argv=args.ToArray();
puts("--- ");
puts("Time Zone: "+(null!=zone?zone.toString():"unspecified"));
for(int i=0; argc-->0; ++i) {
puts("Time "+i+": "+argv[i]);
if(i>0) {
long duration=ClockCant.Subtract(argv[i], argv[i-1], zone);
puts("Duration = "+duration);
}
}
}
static void Main(String[] args) {
Date retainsOfTheDay=ClockCant.MakeTime(1900, 1, 1, 8, 5, 51+0);
Date somewhereInTime=ClockCant.MakeTime(1900, 1, 1, 8, 5, 51+1);
DateTimeZone zone=ClockCant.GetZoneFromId("PRC");
puts("Current Time Zone: "+ClockCant.GetYourZoneId());
puts("Language: "+Language);
ShowDuration(null, retainsOfTheDay, somewhereInTime);
ShowDuration(zone, retainsOfTheDay, somewhereInTime);
}
static String Language="C#";
}
Run Code Online (Sandbox Code Playgroud)
要在Java中编译/*/,请在代码的开头添加a ,如下所示:
/*/// Like Java, like Sharp ...
Run Code Online (Sandbox Code Playgroud)
我相信你的Joda Time测试被打破了,因为你已经使它变得不必要地复杂,基本上.这是一个简短但完整的程序,展示了不同之处:
import java.util.*;
import org.joda.time.*;
public class ChinaTest {
public static void main(String[] args) {
DateTime startOf1900 = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeZone.UTC);
DateTime endOf1899 = startOf1900.minusMillis(1);
DateTimeZone jodaZone = DateTimeZone.forID("Asia/Shanghai");
System.out.println("Joda at start of 1900: " +
jodaZone.getOffset(startOf1900));
System.out.println("Joda at end of 1899: " +
jodaZone.getOffset(endOf1899));
TimeZone javaZone = TimeZone.getTimeZone("Asia/Shanghai");
System.out.println("Java at start of 1900: " +
javaZone.getOffset(startOf1900.getMillis()));
System.out.println("Java at end of 1899: " +
javaZone.getOffset(startOf1900.getMillis() - 1));
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
Joda at start of 1900: 29152000
Joda at end of 1899: 29152000
Java at start of 1900: 29152000
Java at end of 1899: 28800000
Run Code Online (Sandbox Code Playgroud)
所以基本上,Java的时区认为在1900年初有一个过渡,而Joda Time则没有.
正如我以前写的,Java的时区实现基本假设夏令时并没有1900 UTC开始之前存在-所以在夏令时的任何时区是在1900年开始生效,表示过渡.
Joda Time和Noda Time都没有做出这样的假设,这就是你看到差异的原因.
这与Unix时代无关,也与2038无关.这意味着你应该期望java.util.TimeZone在1900年UTC开始之前的任何日期/时间处于该时区的"标准时间".