Encuentre la fecha más cercana, dado un TargetDate y un día de la semana

12

Encuentre la fecha más cercana a un TargetDate para un día de la semana determinado.

Por ejemplo, dada una fecha 20161219y un día de la semana de Friday (6), la respuesta es 20161216.

Otro ejemplo, dada una fecha 20161219y un día de la semana de Wednesday (4), la respuesta es 20161221.

Un último ejemplo, dada una fecha 20161219y un día de la semana de Monday (2), la respuesta es 20161219.

Reglas:

  • El formato de fecha para la entrada y salida debe coincidir. En los ejemplos, usé yyyymmdd, pero puede usar cualquier formato siempre que el año (al menos dos dígitos), el mes y el día del mes sean "legibles por humanos".
  • El día de la semana se ingresa como un entero. En mi ejemplo, el domingo es el primer día de la semana, por lo tanto, es el número del día de la semana 1. Puede tener cualquier numeración del Día de la semana, siempre y cuando la anote cuando difiera del ejemplo.
  • Los años 1970 a 2030 deben ser acomodados.
  • Se permiten herramientas y bibliotecas de fechas de idiomas comunes, pero se otorga credibilidad callejera a aquellos que eligen no usarlas.
  • El menor número de bytes gana.
Brett VanderVeen
fuente
2
¿Podrían las respuestas tomar la fecha en una forma diferente si fuera conveniente? Además, los días de la semana también son inconvenientes para los idiomas que toman el lunes como el primer día de la semana
azul
44
Sí, los estrictos requisitos de formato hacen que esta tarea se trate más de analizar / convertir / formatear que de encontrar la fecha real. OMI habría sido mejor especificarlo en la línea de " Puede aceptar la fecha y el día de la semana en cualquier formato razonable, siempre que use el mismo formato para entrada y salida ". Pero dado que un grupo de personas ya ha enviado respuestas, supongo que debe mantenerse así como está ahora.
sonríe el
@smls estoy de acuerdo. Lección aprendida para la próxima vez.
Brett VanderVeen
1
@BrettVanderVeen No creo que sea demasiado tarde para relajar los requisitos. Puede agregar un comentario a cada una de las (actualmente 8) respuestas sobre la especificación actualizada. Lo he hecho de vez en cuando.
Adám

Respuestas:

1

Perl 6 , 46 bytes

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

Una lambda que acepta dos argumentos: una cadena de fecha en yyyy-mm-ddformato y un número entre semana 1= lunes y 7= domingo.

Explicación:

                           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.

Usando el formato de fecha y día de la semana utilizado en los ejemplos, sería 88 bytes:

{S:g/\-//with ~first *.day-of-week==($^b-2)%7+1,Date.new(|($^a~~/(....)(..)(..)/))-3..*}
smls
fuente
FYI, me relajé en las reglas de formato de fecha y día de la semana. Siéntase libre de volver a enviar.
Brett VanderVeen
@BrettVanderVeen: actualizado.
sonríe el
2

Perl 6 , 83 bytes

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

Intentalo

Expandido

->     # 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
fuente
FYI, me relajé en las reglas de formato de fecha y día de la semana. Siéntase libre de volver a enviar.
Brett VanderVeen
2

JavaScript (ES6), 93 bytes

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

Utiliza %Y-%m-%dformato de fecha. Si %a %b %d %Yes un formato de fecha aceptable, entonces para 82 bytes:

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

Podría guardar otros 2 bytes al requerir Sunday = 10 to Saturday = 16, pero ese es un tonto mapeo de días de la semana. Versión anterior de 141 141 bytes (gracias a @Guedes) que usaba el formato de fecha AAAAMMDD específico, con su explicación:

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

Esto se siente demasiado tiempo. Explicación: Primero, inserta -s en la fecha para obtener el formato ISO que new Dateluego puede analizar. Luego, compara el día deseado con el día real para obtener un valor entre -3y 3para el desplazamiento real. La magia 9proviene de 7(porque %es un módulo de CPU, no es un módulo verdadero) más 3(para el -3desplazamiento) menos 1(porque nestá indexado en 1 y getDayestá indexado en 0). La fecha se convierte de nuevo al formato ISO y se eliminan los caracteres no deseados.

Neil
fuente
Puede guardar un byte cambiando el primer reemplazo a.replace(/(?=..(..)?$)/g,'-')
Washington Guedes
FYI, me relajé en las reglas de formato de fecha y día de la semana. Siéntase libre de volver a enviar.
Brett VanderVeen
1

Python, 150 149 bytes

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

Función sin nombre que toma una cadena s, la fecha como se especifica (utilizando cadena de formato t='%Y%m%d'para la entrada y salida) y un número en [1,7], n.
Inspecciona los siete días a partir de los tres días anteriores a los tres días posteriores a la fecha solicitada.
La semana datetimecomienza el lunes y se basa en cero, por lo que la prueba es (n-2)%7==d.weekday().

Jonathan Allan
fuente
FYI, me relajé en las reglas de formato de fecha y día de la semana. Siéntase libre de volver a enviar.
Brett VanderVeen
1

Bash + coreutils, 50

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

Pruébalo en línea .

  • date -d$1 +%uda el día de la semana (1..7); 1 es lunes
  • Esto se resta del día de entrada de la semana para dar una diferencia de los índices del día. Queremos agregar un factor entre el rango [-3, 3] a la fecha de entrada para obtener la fecha más cercana, por lo que agregamos un factor mágico 9, tomamos el módulo 7 y luego resta 3. El factor mágico 9 es 3 + 7 - 1. El 3 ajusta el rango de entrada para el rango [-3, 3], y se resta nuevamente después del módulo. Se requiere el 7 porque el módulo bash es el mismo que el módulo de la CPU y puede dar resultados de -ve, agregando 7 ajustes en el rango correcto. El -1 se debe a que en la entrada, 1 es domingo, pero con la salida% u, 1 es lunes.
  • El exterior dateluego lo analiza <input date> + <magic factor>daysy lo presenta en el formato AAAAMMDD.
Trauma digital
fuente
FYI, me relajé en las reglas de formato de fecha y día de la semana. Siéntase libre de volver a enviar.
Brett VanderVeen
1

Lenguaje de macros SAS, 110 bytes

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

Un lenguaje de golf terrible pero aquí está la explicación (de adentro hacia afuera):

Cree una macro sque acepte una entrada de fecha dy un día laborable numérico a. Luego %eval(%sysfunc(putn(&d,8.))-4)convierte la fecha en una fecha numérica SAS y la disminuye en 4 días. La intnxfunción devuelve la siguiente aparición del día de la semana especificado. putnluego formatea la fecha de nuevo a aaaammdd e %putimprime la salida en el registro.

J_Lard
fuente
FYI, me relajé en las reglas de formato de fecha y día de la semana. Siéntase libre de volver a enviar.
Brett VanderVeen
1

Mathematica, 85 49 bytes

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

El formato de entrada para las fechas es una lista {2016, 12, 16}o real DateObject(creo que algunas otras funcionan también, pero las he probado). En cualquier caso, el formato de salida coincidirá automáticamente. La numeración del día comienza los 1lunes.

La idea es calcular la diferencia entre el día de la semana de entrada y el día de la semana de destino con #2-#~DateValue~"ISOWeekDay"y luego asignarlo [-3, 3]usando un módulo con desplazamiento (es decir Mod[...,7,-3]). El resultado simplemente se agrega a la fecha de entrada (la unidad predeterminada para la adición de objetos de fecha es días).

Martin Ender
fuente
FYI, me relajé en las reglas de formato de fecha y día de la semana. Siéntase libre de volver a enviar.
Brett VanderVeen
@BrettVanderVeen gracias, editado.
Martin Ender
1

R, 119 77 56 bytes

Función sin nombre que toma dos entradas, la fecha D(cadena) y el día d(numérico).

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

Utiliza la función wday()del lubridatepaquete. Puede convertir convenientemente Dateobjetos en días de la semana con 1un tratamiento predeterminado como domingo.

Editar: E / S ahora es el valor predeterminado de la as.Date()función:"YYYY-mm-dd"

Sin golf y explicado

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                                    
}

Editar: ahora crea una secuencia de +-3días en los que se garantiza que cualquier día de la semana se encuentre. Posteriormente, solo tenemos que coincidir un día, lo que hizo que el problema fuera mucho más fácil.

Billywob
fuente
FYI, me relajé en las reglas de formato de fecha y día de la semana. Siéntase libre de volver a enviar.
Brett VanderVeen
@BrettVanderVeen Gracias, actualizado.
Billywob