Trouvez la date la plus proche, en fonction d'une date cible et d'un jour de la semaine

12

Trouvez la date la plus proche d'une date cible pour un jour de la semaine donné.

Par exemple, étant donné une date 20161219et un jour de la semaine de Friday (6), la réponse est 20161216.

Un autre exemple, étant donné une date 20161219et un jour de semaine Wednesday (4), la réponse est 20161221.

Un dernier exemple, étant donné une date 20161219et un jour de semaine Monday (2), la réponse est 20161219.

Règles:

  • Le format de date pour l'entrée et la sortie doit correspondre. Dans les exemples, j'ai utilisé yyyymmdd, mais vous pouvez utiliser n'importe quel format tant que l'année (au moins deux chiffres), le mois et le jour du mois sont "lisibles par l'homme".
  • Le jour de la semaine est entré sous forme d'entier. Dans mon exemple, le dimanche est le premier jour de la semaine, c'est donc le jour du numéro de semaine 1. Vous pouvez avoir n'importe quel numéro de jour de la semaine, tant que vous le notez lorsqu'il diffère de l'exemple.
  • Les années 1970 à 2030 doivent être adaptées.
  • Les outils de date et les bibliothèques de langue commune sont autorisés, mais le crédit de rue est donné à ceux qui choisissent de ne pas les utiliser.
  • Le moins d' octets gagne.
Brett VanderVeen
la source
2
Les réponses pourraient-elles prendre la date sous une forme différente si cela vous convient? Les jours de la semaine ont également été jugés incommodes pour les langues qui prennent le lundi comme premier jour de la semaine
Blue
4
Oui, les exigences de format strictes rendent cette tâche plus sur l'analyse / conversion / formatage que sur la recherche de date réelle. L'OMI aurait-il été préférable de le spécifier dans le sens de " Vous pouvez accepter la date et le jour de la semaine dans n'importe quel format raisonnable, tant que vous utilisez le même format pour l'entrée et la sortie. ". Mais comme un tas de gens ont déjà soumis des réponses, je suppose qu'il faut les conserver telles qu'elles sont actuellement.
smls
@smls je suis d'accord. Leçon apprise pour la prochaine fois.
Brett VanderVeen
1
@BrettVanderVeen Je ne pense pas qu'il soit trop tard pour assouplir les exigences. Vous pouvez simplement ajouter un commentaire à chacune des réponses (actuellement 8) sur la spécification mise à jour. Je l'ai fait à l'occasion.
Adám

Réponses:

1

Perl 6 , 46 octets

{~first *.day-of-week==$^b,Date.new($^a)-3..*}

Un lambda qui accepte deux arguments: une chaîne de date au yyyy-mm-ddformat et un numéro de jour de semaine entre 1= lundi et 7= dimanche.

Explication:

                           Date.new($^a)       # Construct Date object from first argument.
                                        -3     # Subtract 3 days.
                                          ..*  # Construct a Range from that, to infinity.
  first                   ,                    # Iterate the range, and return first date...
        *.day-of-week==$^b                     # whose weekday number equals the second arg.

En utilisant le format de date et de jour de semaine utilisé dans les exemples, ce serait 88 octets:

{S:g/\-//with ~first *.day-of-week==($^b-2)%7+1,Date.new(|($^a~~/(....)(..)(..)/))-3..*}
smls
la source
Pour info, j'ai assoupli les règles de format de date et de jour de la semaine. N'hésitez pas à resoumettre.
Brett VanderVeen du
@BrettVanderVeen: mis à jour.
smls
2

Perl 6 , 83 octets

->$_,\w{~(Date.new(|m/(....)(..)(..)/)-3...*.day-of-week%7+1==w)[*-1]~~{S:g/"-"//}}

Essayez-le

Étendu

->     # pointy block lambda
  $_,
  \w
{
  ~(  # turn into a Str

    Date.new( |m/(....)(..)(..)/ ) - 3 # three days earlier
    ...                                # generate a sequence
    *.day-of-week % 7 + 1 == w         # stop when the right day is found

  )[*-1]  # the last one

  ~~      # apply the following block

  {
    S:g/"-"//  # remove 「-」
  }
}
Brad Gilbert b2gills
la source
Pour info, j'ai assoupli les règles de format de date et de jour de la semaine. N'hésitez pas à resoumettre.
Brett VanderVeen du
2

JavaScript (ES6), 93 octets

(s,n,d=new Date(s))=>d.setDate(d.getDate()+(n+9-d.getDay())%7-3)&&d.toISOString().slice(0,10)

Utilise le %Y-%m-%dformat de date. Si %a %b %d %Yc'est un format de date acceptable, alors pour 82 octets:

(s,n,d=new Date(s))=>d.setDate(d.getDate()+(n+9-d.getDay())%7-3)&&d.toDateString()

Je pourrais économiser 2 octets supplémentaires en exigeant dimanche = 10 à samedi = 16, mais c'est un jour stupide de la cartographie de la semaine. Version précédente de 142 141 octets (merci à @Guedes) qui utilisait le format de date spécifique YYYYMMDD, avec son explication:

(s,n,d=new Date(s.replace(/(?=..(..)?$)/g,'-')))=>d.setDate(d.getDate()+(n+9-d.getDay())%7-3)&&d.toISOString().replace(/-(..)-(..).*/,'$1$2')

Cela semble beaucoup trop long. Explication: Premièrement, insère -s dans la date pour la mettre au format ISO qui new Datepeut ensuite être analysée. Ensuite, compare le jour souhaité avec le jour réel pour obtenir une valeur entre -3et 3pour le décalage réel. La magie 9vient de 7(parce qu'il %s'agit du CPU modulo, pas du vrai modulo) plus 3(pour l' -3offset) moins 1(parce qu'il nest indexé 1 et indexé getDay0). La date est ensuite reconvertie au format ISO et les caractères indésirables supprimés.

Neil
la source
Vous pouvez enregistrer un octet en changeant le premier remplacement en.replace(/(?=..(..)?$)/g,'-')
Washington Guedes
Pour info, j'ai assoupli les règles de format de date et de jour de la semaine. N'hésitez pas à resoumettre.
Brett VanderVeen du
1

Python, 150 149 octets

from datetime import*
lambda s,n,t='%Y%m%d':[d for d in[datetime.strptime(s,t)+timedelta(o-3)for o in range(7)]if(n-2)%7==d.weekday()][0].strftime(t)

Oouuf, 149. repl.it

Sans nom fonction qui prend une chaîne s, la date comme spécifié ( en utilisant la chaîne de format t='%Y%m%d'pour l'entrée et la sortie) et un certain nombre de [1,7], n.
Inspecte les sept jours, de trois jours avant à trois jours après celui donné pour le jour de la semaine demandé.
La semaine datetimecommence le lundi et est basée sur zéro, donc le test est (n-2)%7==d.weekday().

Jonathan Allan
la source
Pour info, j'ai assoupli les règles de format de date et de jour de la semaine. N'hésitez pas à resoumettre.
Brett VanderVeen du
1

Bash + coreutils, 50

date -d$1+$[($2-`date -d$1 +%u`+9)%7-3]day +%Y%m%d

Essayez-le en ligne .

  • date -d$1 +%udonne le jour de la semaine (1..7); 1 est lundi
  • Ceci est soustrait du jour de la semaine d'entrée pour donner une différence d'index de jour. Nous voulons ajouter un facteur compris entre [-3, 3] à la date d'entrée pour obtenir la date la plus proche, nous ajoutons donc un facteur magique 9, prenons le modulo 7, puis soustrayons 3. Le facteur magique 9 est 3 + 7 - 1. Le 3 ajuste la plage d'entrée pour la plage [-3, 3] et est à nouveau soustrait après le modulo. Le 7 est requis car bash modulo est le même que CPU modulo et peut donner des résultats -ve - en ajoutant 7 ajuste dans la bonne plage. Le -1 est parce que dans l'entrée, 1 est dimanche, mais avec la sortie% u, 1 est lundi.
  • L'extérieur dateanalyse ensuite <input date> + <magic factor>dayset le présente au format AAAAMMJJ.
Traumatisme numérique
la source
Pour info, j'ai assoupli les règles de format de date et de jour de la semaine. N'hésitez pas à resoumettre.
Brett VanderVeen du
1

Langage macro SAS, 110 octets

%macro s(d,a);%put %sysfunc(putn(%sysfunc(intnx(week.&a.,%eval(%sysfunc(putn(&d,8.))-4),1)),yymmddn8.));%mend;

Un langage de golf terrible mais voici l'explication (de l'intérieur):

Créez une macro squi accepte une entrée de date det un jour de semaine numérique a. %eval(%sysfunc(putn(&d,8.))-4)Convertit ensuite la date en une date numérique SAS et la diminue de 4 jours. La intnxfonction renvoie ensuite l'occurrence suivante du jour de la semaine spécifié. putnformate ensuite la date en aaaammjj et %putimprime la sortie dans le journal.

J_Lard
la source
Pour info, j'ai assoupli les règles de format de date et de jour de la semaine. N'hésitez pas à resoumettre.
Brett VanderVeen du
1

Mathematica, 85 49 octets

#~DatePlus~Mod[#2-#~DateValue~"ISOWeekDay",7,-3]&

Le format d'entrée pour les dates est soit une liste comme {2016, 12, 16}ou une réelle DateObject(je pense que quelques autres fonctionnent aussi, mais je les ai testées). Dans les deux cas, le format de sortie correspondra automatiquement. La numérotation des jours commence 1le lundi.

L'idée est de calculer la différence entre le jour de la semaine en entrée et le jour de la semaine cible avec #2-#~DateValue~"ISOWeekDay", puis de le mapper en [-3, 3]utilisant un modulo avec décalage (c. Mod[...,7,-3]-à-d.). Le résultat est simplement ajouté à la date d'entrée (l'unité par défaut pour l'ajout d'objet de date est jours).

Martin Ender
la source
Pour info, j'ai assoupli les règles de format de date et de jour de la semaine. N'hésitez pas à resoumettre.
Brett VanderVeen du
@BrettVanderVeen merci, édité.
Martin Ender
1

R, 119 77 56 octets

Fonction sans nom qui prend deux entrées, la date D(chaîne) et le jour d(numérique).

function(D,d,s=-3:3+as.Date(D))s[lubridate::wday(s)==d]

Utilise la fonction wday()du lubridatepackage. Il peut facilement convertir des Dateobjets en jours de la semaine en 1étant traité comme dimanche par défaut.

Edit: I / O est maintenant la valeur par défaut de la as.Date()fonction:"YYYY-mm-dd"

Non golfé et expliqué

function(D,d){
    D=as.Date(D);            # Format input date
    s=-3:3+D;                # Generate sequence of +- 3 days
    s[lubridate::wday(s)==d] # Match the weekday that equals to target day                                    
}

Modifier: crée maintenant une séquence de +-3jours pour laquelle un jour de semaine donné est garanti. Par la suite, nous n'avons à faire correspondre qu'un seul jour, ce qui a rendu le problème beaucoup plus facile.

Billywob
la source
Pour info, j'ai assoupli les règles de format de date et de jour de la semaine. N'hésitez pas à resoumettre.
Brett VanderVeen du
@BrettVanderVeen Merci, mis à jour.
Billywob