Pregunta Explicación de las diferencias de Timespan entre C # y JavaScript


Esto se basa en La computación de milisegundos desde 1970 en C # produce una fecha diferente a la de JavaScript y Versión de C # de Javascript Date.getTime ().

Para todos estos cálculos, suponga que se están realizando en el horario estándar central, por lo que 6 horas detrás de UTC (este desplazamiento volverá a aparecer más adelante).

Entiendo que JavaScript Date los objetos se basan en el Unix Epoch (Medianoche del 1 de enero de 1970). Entonces, si lo hago:

//remember that JS months are 0-indexed, so February == 1
var d = new Date(2014,1,28);
d.getTime();

Mi salida será:

1393567200000

Lo que representa el número de milisegundos desde la Época Unix. Eso está muy bien. En las preguntas vinculadas, las personas preguntaban acerca de cómo traducir esta funcionalidad a C # y la implementación "ingenua" generalmente se ve así:

//the date of interest in UTC
DateTime e = new DateTime(2014, 2, 28, 0, 0, 0, DateTimeKind.Utc);
//the Unix Epoch
DateTime s = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
//the difference between the two
TimeSpan t = (e - s);
var x = t.TotalMilliseconds;
Console.WriteLine(x);

Que produce salida:

1393545600000

Esa es una diferencia de 21,600,000 milisegundos, o 6 horas: la compensación exacta de UTC para la zona horaria en la que se realizaron estos cálculos.

Para que la implementación de C # coincida con el JavaScript, esta es la implementación:

//DateTimeKind.Unspecified
DateTime st=new DateTime(1970,1,1);
//DateTimeKind.Unspecified
DateTime e = new DateTime(2014,2,28);
//translate e to UTC, but leave st as is
TimeSpan t= (e.ToUniversalTime()-st);
var x = t.TotalMilliseconds;
Console.WriteLine(x);

Lo cual me dará un resultado que coincida con el resultado de JavaScript:

1393567200000

Lo que aún tengo que encontrar es una explicación de por qué dejamos el DateTime representando la Época Unix con un DateTimeKind de Unspecified para poder hacer coincidir JavaScript ¿No deberíamos obtener el resultado correcto usando DateTimeKind.Utc? ¿Qué detalle no estoy entendiendo? Esta es una pregunta puramente académica para mí, solo tengo curiosidad sobre por qué esto funciona de esta manera.


9
2018-02-28 13:31


origen


Respuestas:


Como correctamente señalas, .getTime() devoluciones "la cantidad de milisegundos desde el 1 de enero de 1970 a las 00:00:00 UTC".

Lo que significa que .getTime es (como ha notado) incluyendo el desplazamiento de UTC en el cálculo.

Para hacer que el código C # refleje esto, el tiempo que está restando de debe incluye información de zona horaria, mientras que el 1 de enero de 1970 00:00:00 debe ser una hora UTC.

Esto podría ser más fácil de entender con algunos ejemplos. Dado:

DateTime e = new DateTime(2014, 2, 28, 0, 0, 0);
DateTime s = new DateTime(1970, 1, 1, 0, 0, 0);
  1. e - s es incorrecto porque s no es una hora UTC.
  2. e.ToUniversalTime() - s.ToUniversalTime() es incorrecto porque e ya no incluye el desplazamiento de UTC (como hace el cálculo en JavaScript)
  3. e.ToUniversalTime() - s  es correcto porque estamos usando la hora UTC y el tiempo que estamos restando incluye el desplazamiento de UTC.

Esto fue más fácil para mí ver cuando lidié con DateTime.Ticks directamente:

e.Ticks // 635291424000000000
s.Ticks // 621355968000000000

e.Ticks - s.Ticks // 13935456000000000 ("naive" implementation)
e.ToUniversalTime().Ticks - s.Ticks // 13935636000000000 (correct output)

Nuevamente, el último ejemplo cumple con todos nuestros requisitos. La época de Unix está en UTC, mientras que el tiempo que estamos tratando todavía tiene su compensación original.


6
2018-02-28 14:03



Entiendo que los objetos Date de JavaScript se basan en la Época Unix (medianoche del 1 de enero de 1970).

Sí lo son. Internamente, es solo un número de milisegundos de la época. Pero cuando llamas al constructor de la fecha, o miras el resultado de .toString(), está utilizando la hora local de donde se está ejecutando el código.

Si desea que la entrada se especifique en UTC, entonces debe usar un conjuro diferente:

var ts = Date.UTC(2014,1,28);  // returns a numeric timestamp, not a Date object

var dt = new Date(ts);         // if you want a date object

var s = dt.toUTCString();      // if you want the output to be in UTC

2
2018-03-02 23:45