7
votes

Comment détecter si les dates sont consécutives en python?

J'ai une table d'accès avec un champ "Date". Il a des dates aléatoires pour chaque enregistrement. J'ai construit un script pour ajouter tous les enregistrements dans une liste, puis définir la liste pour filtrer uniquement les valeurs uniques: xxx

Ce retour (sur ma table de test):

['07-06-2010', '07 -05-2010 ', '06 -25-2010']

maintenant que j'ai l'unique Valeurs pour le champ "date_observation", je souhaite détecter si:

  • Les dates sont célibataires (c'est-à-dire une seule date unique est renvoyée car c'est la date à chaque enregistrement)
  • Si les dates sont une gamme de dates (c'est-à-dire toutes les dates relevant d'une plage consécutive)
  • Si les dates sont plusieurs dates, mais ne sont pas dans une gamme de dates consécutives

    Toute suggestion serait très appréciée! Mike


4 commentaires

Courte Répondre paresseuse: Convertissez-les en objets DateTime, triez-les puis utilisez la recette par paires à partir de la page iTertools DOC pour comparer toutes les dates sur la liste suivante dans la liste pour voir si C'est une gamme; Pour les dates simples, prenez la date du premier et vérifiez que tous les autres sont dans le même jour de calendrier; Si ces deux échaissent sont des dates disparates.


Si vous ne sélectionnez pas d'autres valeurs, utilisez Sélectionnez Date_observation à partir d'une commande MyTable par date_observation Desc et ne convertissez pas les dates en cordes ..


@Deathpril: Pourquoi la commande descendante?


@ J.f.sebastian euh , aucune raison - j'ai vu '07 -06-2010 ', '06 -24-2010' dans la question et ignoré le reste des exemples, je suppose ..


4 Réponses :


16
votes

Plutôt que de rouler votre propre Fonction consécutive Vous pouvez simplement convertir des objets de date en entiers à l'aide de la méthode .POORDININAL () Méthode d'objets DateTime. La différence entre la valeur maximale et minimale de l'ensemble des dates ordinales est une longueur de plus que la longueur de l'ensemble: xxx


4 commentaires

Merci Michael. Cela a bien fonctionné avec mon script! J'apprécie votre réponse.


@Michael Dillon: Sélectionnez Distinct .. Comme dans le commentaire de @ Deathapril est encore meilleur.


Si nous considérons ['01 -01-2000 ', '01 -01-2000', '01 -02-2000 '] Pour ne pas être consécutifs, l'utilisation de ce code indiquera que les dates sont consécutives, comment pourriez-vous modifier votre code à considérer cette exigence? Je ne sais pas à quel point les ensembles fonctionnent encore.


@ MOASTHANL0L: Définit les doublons. Si vous souhaitez envisager une liste avec des doublons comme non consécutive, vous pouvez vérifier si la longueur de votre liste de dates est supérieure à la longueur de l'ensemble des dates.



0
votes

Utilisez votre base de données pour sélectionner des dates uniques dans la commande ascendante:

  • Si la requête renvoie une seule date, c'est votre premier cas p> li>

  • sinon découvrez si les dates sont consécutives: p>

    dates = <query database>
    if all(consecutive(dates[i], dates[i+1]) for i in xrange(len(dates) - 1)):
       if len(dates) == 1: # unique
          # 1st case: all records have the same date
       else:
          # the dates are a range of dates
    else:
       # non-consecutive dates
    


0 commentaires

0
votes

Voici ma version à l'aide de la fonction Réduire ().

from datetime import date, timedelta


def checked(d1, d2):
    """
    We assume the date list is sorted.
    If d2 & d1 are different by 1, everything up to d2 is consecutive, so d2
    can advance to the next reduction.
    If d2 & d1 are not different by 1, returning d1 - 1 for the next reduction
    will guarantee the result produced by reduce() to be something other than
    the last date in the sorted date list.

    Definition 1: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider consecutive
    Definition 2: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider not consecutive

    """
    #if (d2 - d1).days == 1 or (d2 - d1).days == 0:  # for Definition 1
    if (d2 - d1).days == 1:                          # for Definition 2
        return d2
    else:
        return d1 + timedelta(days=-1)

# datelist = [date(2014, 1, 1), date(2014, 1, 3),
#             date(2013, 12, 31), date(2013, 12, 30)]

# datelist = [date(2014, 2, 19), date(2014, 2, 19), date(2014, 2, 20),
#             date(2014, 2, 21), date(2014, 2, 22)]

datelist = [date(2014, 2, 19), date(2014, 2, 21),
            date(2014, 2, 22), date(2014, 2, 20)]

datelist.sort()

if datelist[-1] == reduce(checked, datelist):
    print "dates are consecutive"
else:
    print "dates are not consecutive"


0 commentaires

1
votes

Une autre version en utilisant la même logique que dans mon autre réponse.

from datetime import date, timedelta

# Definition 1: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider consecutive
# Definition 2: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider not consecutive

# datelist = [date(2014, 1, 1), date(2014, 1, 3),
#             date(2013, 12, 31), date(2013, 12, 30)]

# datelist = [date(2014, 2, 19), date(2014, 2, 19), date(2014, 2, 20),
#             date(2014, 2, 21), date(2014, 2, 22)]

datelist = [date(2014, 2, 19), date(2014, 2, 21),
            date(2014, 2, 22), date(2014, 2, 20)]

datelist.sort()

previousdate = datelist[0]

for i in range(1, len(datelist)):
    #if (datelist[i] - previousdate).days == 1 or (datelist[i] - previousdate).days == 0:  # for Definition 1
    if (datelist[i] - previousdate).days == 1:    # for Definition 2
        previousdate = datelist[i]
    else:
        previousdate = previousdate + timedelta(days=-1)

if datelist[-1] == previousdate:
    print "dates are consecutive"
else:
    print "dates are not consecutive"


0 commentaires