Différence entre 2 dates dans SQLite


110

Comment obtenir la différence en jours entre 2 dates dans SQLite? J'ai déjà essayé quelque chose comme ça:

SELECT Date('now') - DateCreated FROM Payment

Il renvoie 0 à chaque fois.

Réponses:


123
 SELECT julianday('now') - julianday(DateCreated) FROM Payment;

10
Notez que malgré ce que le nom de la fonction pourrait faire penser, cela a une granularité plus élevée que les jours. C'est un certain nombre de jours, mais cela peut être fractionné.
lindes le

10
Gardez à l'esprit que julianday renvoie le nombre (fractionnaire) de «jours», c'est-à-dire des périodes de 24 heures, depuis midi UTC à la date d'origine. Ce n'est généralement pas ce dont vous avez besoin, sauf si vous habitez 12 heures à l'ouest de Greenwich. Par exemple, si vous vivez à Londres, ce matin est le même jour de juillet qu'hier après-midi.
JulianSymes

2
Cela fonctionne si vous DateCreatedêtes en UTC. Si, à la place, c'est l'heure locale, vous devez convertir julianday('now')en heure locale. Je n'ai trouvé aucun endroit contenant cette information. Si vous faites julianday('now') - julianday(DateCreated)comme ce message suggère avec une date stockée dans l'heure locale, votre réponse sera décalée de votre décalage par rapport à GMT et sera erronée. Bien que ce ne soit peut-être pas la meilleure pratique de stocker les dates à l'heure locale, cela peut toujours se produire dans les applications où les fuseaux horaires n'ont pas d'importance (sauf lorsque l'outil avec lequel vous travaillez les force sur vous, comme ici).
vapcguy

3
En supposant que DateCreated est à l'heure locale, si vous le faites julianday('now') - julianday(DateCreated, 'utc'), pour faire les deux UTC, cela ne fonctionne pas de la même manière que le faire julianday('now', 'localtime') - julianday(DateCreated). Le premier ne tient pas compte des jours DST et ajoutera une heure supplémentaire aux dates créées en mars-novembre. Ce dernier en rend compte. stackoverflow.com/questions/41007455/…
vapcguy

60

Différence en jours

Select Cast ((
    JulianDay(ToDate) - JulianDay(FromDate)
) As Integer)

Différence en heures

Select Cast ((
    JulianDay(ToDate) - JulianDay(FromDate)
) * 24 As Integer)

Différence en minutes

Select Cast ((
    JulianDay(ToDate) - JulianDay(FromDate)
) * 24 * 60 As Integer)

Différence en secondes

Select Cast ((
    JulianDay(ToDate) - JulianDay(FromDate)
) * 24 * 60 * 60 As Integer)

1
pour sqlite version 3.12.0, l'expression cast a le type AS entre crochets. par exemple "Sélectionnez Cast (5.6 As Integer)"; sqlite.org/lang_expr.html#castexpr Sinon, des exemples vraiment utiles.
rob

Merci @rob. Quelqu'un a proposé de m'éditer comme ça avant. Mais quand je l'ai essayé dans Sqlitebrowser, cela ne fonctionnait pas. Peut-être que c'est parce qu'il s'agit d'une version plus ancienne. Alors je l'ai gardé tel quel ..
Sayka

Je viens d'utiliser SQLitebrowser et j'ai mentionné l'erreur rob .. Puis-je modifier votre message avec le libellé moderne?
Noumenon le

@Noumenon veuillez proposer votre modification. Je vais le vérifier dans sqlitebrowser ici et si cela fonctionne, j'approuverai sûrement votre modification. Merci pour votre temps.
Sayka le

2
Cette réponse est beaucoup plus remplie de fonctionnalités que la réponse acceptée, à mon humble avis.
Marcus Parsons

33

Les deux réponses fournissent des solutions un peu plus complexes, comme il se doit. Supposons que le paiement a été créé le January 6, 2013. Et nous voulons connaître la différence entre cette date et aujourd'hui.

sqlite> SELECT julianday() - julianday('2013-01-06');
34.7978485878557 

La différence est de 34 jours. Nous pouvons utiliser julianday('now')pour une meilleure clarté. En d'autres termes, nous n'avons pas besoin de mettre date()ou de datetime()fonctions comme paramètres pour julianday() fonctionner.


Je ne suis pas sûr, mais si cette commande était dans le code et que la valeur du 6 janvier 2013 provenait de la base de données, il faut tenir compte du type de données utilisé.
NoChance

23

La documentation SQLite est une excellente référence et la page DateAndTimeFunctions est une bonne à mettre en signet.

Il est également utile de se rappeler qu'il est assez facile de jouer avec des requêtes avec l'utilitaire de ligne de commande sqlite:

sqlite> select julianday(datetime('now'));
2454788.09219907
sqlite> select datetime(julianday(datetime('now')));
2008-11-17 14:13:55

1
Étant donné que cette page est fournie avec un classement des moteurs de recherche Google, voici le lien actuel: sqlite.org/lang_datefunc.html
markusN

9

Cette réponse est un peu longue et la documentation ne vous le dira pas (car ils supposent que vous stockez vos dates sous forme de dates UTC dans la base de données), mais la réponse à cette question dépend en grande partie du fuseau horaire dans lequel vos dates sont stockées Vous n'utilisez pas non plus Date('now'), mais utilisez la julianday()fonction, pour calculer les deux dates par rapport à une date commune, puis soustrayez la différence de ces résultats l'un de l'autre.

Si vos dates sont stockées en UTC:

SELECT julianday('now') - julianday(DateCreated) FROM Payment;

C'est ce que contient la réponse la mieux classée et se trouve également dans la documentation . Ce n'est qu'une partie de l'image, et une réponse très simpliste, si vous me le demandez.

Si vos dates sont stockées à l'heure locale, l'utilisation du code ci-dessus rendra votre réponse erronée du nombre d'heures de votre décalage GMT. Si vous êtes dans l'est des États-Unis comme moi, qui est GMT -5, votre résultat aura 5 heures supplémentaires. Et si vous essayez de vous DateCreatedconformer à UTC car julianday('now')va à l'encontre d'une date GMT:

SELECT julianday('now') - julianday(DateCreated, 'utc') FROM Payment;

Cela a un bogue où il ajoutera une heure pour un DateCreatedqui est pendant l'heure d'été (mars-novembre). Dites que «maintenant» est à midi un jour sans heure d'été et que vous avez créé quelque chose en juin (pendant l'heure d'été) à midi, votre résultat donnera 1 heure d'intervalle, au lieu de 0 heure, pour la partie heures. Vous devrez écrire une fonction dans le code de votre application qui affiche le résultat pour modifier le résultat et soustraire une heure des dates DST. Je l'ai fait, jusqu'à ce que je réalise qu'il y avait une meilleure solution à ce problème que j'avais: SQLite vs Oracle - Calcul des différences de date - heures

Au lieu de cela, comme cela m'a été indiqué, pour les dates stockées à l'heure locale, faites correspondre les deux à l'heure locale:

SELECT julianday('now', 'localtime') - julianday(DateCreated) FROM Payment;

Ou ajouter 'Z'à l'heure locale:

julianday(datetime('now', 'localtime')||'Z') - julianday(CREATED_DATE||'Z')

Les deux semblent compenser et n'ajoutent pas l'heure supplémentaire pour les dates DST et font une soustraction directe - de sorte que l'élément créé à midi un jour DST, lors de la vérification à midi un jour non DST, n'aura pas une heure supplémentaire lorsque effectuer le calcul.

Et bien que je reconnaisse que la plupart diront de ne pas stocker les dates à l'heure locale dans votre base de données et de les stocker en UTC afin de ne pas rencontrer cela, toutes les applications n'ont pas un public mondial, et tous les programmeurs ne le souhaitent pas. pour passer par la conversion de CHAQUE date dans leur système en UTC et inversement chaque fois qu'ils font un GET ou un SET dans la base de données et s'occupent de déterminer si quelque chose est local ou UTC.


"Ce n'est qu'une partie de l'image, et une réponse très simpliste, si vous me demandez." Oui vous avez raison. Mais ma réponse a été donnée 3 minutes après qu'il ait posé sa question lorsque la vôtre arrive deux ans plus tard. Simpliste mais elle semblait lui convenir.
Fred

1
@Fred Assez bien. Mais cela a fini par m'emmener faire un tour, comme je l'ai décrit ci-dessus, et ne m'a donc pas aidé. Je voulais être sûr que quiconque verrait cela à l'avenir savait exactement ce qui se passait pour ne pas tomber dans les mêmes pièges que moi - ou, s'ils le faisaient, ils sauraient comment s'en sortir.
vapcguy

@Fred, c'est une très bonne explication et je ne sais pas trop à quoi s'attendre? Peut-être postez votre réponse?
NoChance

Merci pour votre explication. Je ne suis pas sûr que les gens de SQLite aient décidé d'aller à l'encontre des normes que les gens ont appris à accepter au fil des ans et se sont retrouvés avec une implémentation inutilement complexe et difficile à tester dans un aspect critique tel que la date et l'heure! Imaginez le nombre de cas de test requis pour vérifier que chaque date dans l'application fonctionne comme les humains l'attendent!
NoChance

3

Juste une note pour écrire les fonctions de l'horloge. Pour ceux qui recherchent des heures travaillées, un changement très simple de ceci obtient les heures plus les minutes sont affichées sous forme de pourcentage de 60 comme le veulent la plupart des sociétés de paie.

CAST ((julianday(clockOUT) - julianday(clockIN)) * 24 AS REAL) AS HoursWorked

Clock In            Clock Out           HoursWorked
2016-08-07 11:56    2016-08-07 18:46    6.83333332836628

Petite question
intéressante

3

Si vous voulez l'heure au format 00:00: je l'ai résolu comme ça:

select strftime('%H:%M',CAST ((julianday(FinishTime) - julianday(StartTime)) AS REAL),'12:00') from something

2

Étant donné que votre format de date est le suivant: "AAAA-MM-JJ HH: MM: SS", si vous avez besoin de trouver la différence entre deux dates en nombre de mois:

(strftime('%m', date1) + 12*strftime('%Y', date1)) - (strftime('%m', date2) + 12*strftime('%Y', date2))


2

Premièrement, le format de votre date n'est pas clair. Il existe déjà une réponse impliquant strftime("%s").

J'aime développer cette réponse.

SQLite n'a que les classes de stockage suivantes: NULL, INTEGER, REAL, TEXT ou BLOB. Pour simplifier les choses, je vais supposer que les dates sont REAL contenant les secondes depuis le 01/01/1970. Voici un exemple de schéma pour lequel je vais mettre dans les exemples de données du "1er décembre 2018":

CREATE TABLE Payment (DateCreated REAL);
INSERT INTO Payment VALUES (strftime("%s", "2018-12-01"));

Calculons maintenant la différence de date entre le "1er décembre 2018" et maintenant (au moment où j'écris ceci, nous sommes le 12 décembre 2018 à midi):

Différence de date en jours:

SELECT (strftime("%s", "now") - DateCreated) / 86400.0 FROM Payment;
-- Output: 11.066875

Différence de date en heures:

SELECT (strftime("%s", "now") - DateCreated) / 3600.0 FROM Payment;
-- Output: 265.606388888889

Différence de date en minutes:

SELECT (strftime("%s", "now") - DateCreated) / 60.0 FROM Payment;
-- Output: 15936.4833333333

Différence de date en secondes:

SELECT (strftime("%s", "now") - DateCreated) FROM Payment;
-- Output: 956195.0

2

Si vous voulez une différence en quelques secondes

SELECT strftime('%s', '2019-12-02 12:32:53') - strftime('%s', '2019-12-02 11:32:53')

0

Si vous voulez des enregistrements entre les jours,

select count(col_Name) from dataset where cast(julianday("now")- julianday(_Last_updated) as int)<=0;

0

Dans mon cas, je dois calculer la différence en minutes et julianday()ne donne pas de valeur précise. Au lieu de cela, j'utilise strftime():

SELECT (strftime('%s', [UserEnd]) - strftime('%s', [UserStart])) / 60

Les deux dates sont converties en unixtime (secondes), puis soustraites pour obtenir une valeur en secondes entre les deux dates. Ensuite, divisez-le par 60.

https://www.sqlite.org/cvstrac/wiki?p=DateAndTimeFunctions

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.