Rebranchez-le ce soir ou ce week-end

20

Ceci est mon premier code de golf, alors faites-le moi savoir s'il est trop large ou s'il manque des informations pour un bon puzzle!

Défi

En Ontario et peut-être dans d'autres régions du monde, l'électricité est facturée en fonction de la tarification horaire (TOU) , qui fait varier le coût par kilowattheure selon le moment où vous utilisez l'électricité.

Étant donné une date et une heure, je veux savoir si je suis dans une période de pointe (rouge), moyenne (jaune) ou hors pointe (verte).

Contribution

Supposons que l'entrée est fournie dans un format de date-heure ISO 8601 sans fuseau horaire acceptable avec la précision minimale des heures: YYYY-MM-DDThh[:mm[:ss]](le T est littéral).

Exemples

  • 2014-09-01T14
  • 2014-09-01T17: 30
  • 2014-09-01T17: 30: 02

Production

La sortie doit être une chaîne On, Midou Off.

Règles

  • Victoires de code les plus courtes
  • Aux fins de ce défi, ignorez les jours fériés
  • Supposons les informations trouvées dans ce post. Les règles actuelles de tarification en fonction du temps d'utilisation pourraient changer à l'avenir par le ministère de l'Énergie de l'Ontario.

Information

Jours de semaine d'été (1er mai au 31 octobre)

Horloge de temps d'utilisation pour les jours de semaine d'été

  • Hors pointe: 19h00 - 07h00
  • Mi-pic: 07h00 - 11h00 et 17h00 - 19h00
  • En pointe: 11h00 - 17h00

En semaine en hiver (du 1er novembre au 30 avril)

Horloge de temps d'utilisation pour les jours de semaine d'hiver

  • Hors pointe: 19h00 - 07h00
  • Mi-pic: 11h00 - 17h00
  • En période de pointe: 07h00 - 11h00 et 17h00 - 19h00

Fins de semaine

Horloge de temps d'utilisation le week-end

  • Hors pointe: toute la journée
rink.attendant.6
la source
Êtes-vous sûr que les jours de semaine d'hiver ne sont pas échangés entre les heures de pointe et les heures de pointe?
John Dvorak
3
@JanDvorak, en hiver, les gens utilisent la lumière et le chauffage le matin et le soir; en été, ils utilisent l'air conditionné à midi.
Peter Taylor
4
Il s'agit d'un doublon limite de codegolf.stackexchange.com/q/7008/194 (analyser une date et faire un calcul simple selon qu'il s'agit d'une journée de travail ou non). Je pense que la dépendance de la saison est juste assez différente, mais d'autres peuvent être en désaccord.
Peter Taylor
@PeterTaylor les règles semblent beaucoup plus simples ici que dans la question liée. Cela n'a pas à gérer les années bissextiles, par exemple.
John Dvorak du
3
Le format général de la date doit-il être YYYY-MM-DDThh[:mm[:ss]]puisque les secondes ne peuvent être appliquées que si des minutes sont appliquées?
Cruncher

Réponses:

3

Rubis - 147 144 143 141 141 137 135

x=->s{y,m,d,h=s.scan(/\d+/).map &:to_i
g=Time.new(y,m,d).wday%6<1?0:[0..11,4..9].count{|r|r===h-7}
%W{Off Mid On}[m<5||m>10?(3-g)%3:g]}

Cela représente une fonction qui prend une chaîne en paramètre et renvoie une chaîne.

Voici une démo en ligne avec quelques cas de test: http://ideone.com/wyIydw

Cristian Lupascu
la source
8

Python 2 - 164

from datetime import*
d,t=input().split('T')
y,m,d=map(int,d.split('-'))
t=int(t[:2])
print'OMOfinfd'[(1+((10<t<17)==(4<m<11)))*(date(y,m,d).weekday()<5<6<t<19)::3]

Si nécessaire, voici une explication de la logique dans la dernière ligne:

La ligne finale imprime une tranche en 'OMOfinfd'fonction de l'évaluation de ses conditions.

  • Évaluez d'abord l'opération 1+((10<t<17)==(4<m<11)).

    Si le XNOR entre les conditions 10<t<17et 4<m<11est False, cela sera évalué à 1+False => 1+0 => 1. Sinon, l'opération sera évaluée à 1+True => 1+1 => 2.

  • Enfin, multipliez ce résultat de l'opération ci-dessus par si le jour est un jour de semaine et si l'heure est comprise entre 6 heures-19 heures.

    Si c'est le cas False, le jour est un week-end ou le temps est entre 19 heures-6 heures, et le résultat sera (1|2)*0 => 0. Sinon, le résultat sera (1|2)*1 => 1|2.

Un résultat de 0sera imprimé Off, 1imprimera Midet 2imprimera On.

BeetDemGuise
la source
La version golfée n'est-elle pas réellement plus longue car vous utilisez des points-virgules? Ou les nouvelles lignes sont-elles comptées?
Beta Decay
Les retours à la ligne sont généralement comptés. Dans Notepad ++ (où j'obtiens généralement mes comptes), la version non golfée est 4 octets de plus à 168.
BeetDemGuise
3
@BeetDemGuise Edit → Conversion EOL → Format UNIX / OSX.
Schism
5

C # - 240 220 caractères

string x(string s){var d=DateTime.Parse((s+":00:00").Substring(0,19));int h=d.Hour,i=(int)d.DayOfWeek,x=d.Month;string o="off",m="mid",f="on";return i==6|i==0?o:x>=5&x<11?h>18|h<7?o:h>10&h<17?f:m:h>18|h<7?o:h>10&h<17?m:f;}

Rien de spécial. Codage simple.

Merci à w0lf :)

Stephan Schinkel
la source
1
Je pense que vous pouvez raccourcir s.Length==13?s+":00:00":s.Length==16?s+":00":sà(s+":00:00").Substring(0,19)
Cristian Lupascu
5

Rubis - 135

Abuse le module Temps. Entrée par argument de ligne de commande.

d=Time.new(*$*[0].scan(/\d+/)[0..3])
o,m,f=%w{On Mid Off}
o,m=m,o if (d.mon-5)%10<6
p d.wday%6<1||(12>h=(d.hour+5)%24)?f:15<h&&h<22?m:o

Edit: Merci w0lf pour le temps qui a permis de raccourcir et de résoudre un bug.

Vectorisé
la source
Votre programme est incorrect. Pour l'entrée, 2014-09-01T17:30il sort correctement "Mid", mais pour 2014-09-01T17il sort "Off".
Cristian Lupascu
3

Groovy - 621 534 524 491 caractères

Un peu plus de golf à faire, mais assez simple quand on utilise Joda-Time

@Grab(group='joda-time',module='joda-time',version='2.3')
f={p,a->org.joda.time.format.DateTimeFormat.forPattern(p).parseDateTime a}
g={p,a->def x=null;try{x=f p,a}catch(Exception e){}}
a=args[0]
d=["",":mm",":mm:ss"].collect{g "yyyy-MM-dd'T'HH$it",a}.find{it}
r="Off"
m="Mid"
j={d,a,b->d.hourOfDay>a&&d.hourOfDay<b}
k={j(it,6,11)||(j(it,16,19))}
if(d.dayOfWeek<6){x=d.monthOfYear;if(x>4&&x<12){if(j(d,10,17))r="On";if(k(d))r=m}else if(x<5||x>10){if(j(d,10,17))r=m;if(k(d))r="On"}}
println r

échantillons:

bash-3.2$ ./run.peak.sh 
groovy Peak.groovy 2014-08-26T19
Off
groovy Peak.groovy 2014-08-26T07:00
Mid
groovy Peak.groovy 2014-08-26T18:00:00
Mid
groovy Peak.groovy 2014-08-26T12:30:30
On
groovy Peak.groovy 2014-11-01T00
Off
groovy Peak.groovy 2014-02-05T11:11:11
Mid
groovy Peak.groovy 2014-01-05T08:08
Off
groovy Peak.groovy 2014-12-18T18:59:59
On
groovy Peak.groovy 2014-08-31T14
Off

Non golfé:

@Grab(group='joda-time',module='joda-time',version='2.3')

f = { p,a -> org.joda.time.format.DateTimeFormat.forPattern(p).parseDateTime a}
g = { p,a -> def x=null; try{x=f p,a} catch(Exception e) {} }
a=args[0]

d = ["",":mm",":mm:ss"].collect{g "yyyy-MM-dd'T'HH$it",a}.find{it}
r = "Off"
m = "Mid"

j = {d,a,b -> d.hourOfDay > a && d.hourOfDay < b}
k = { j(it,6,11) || (j(it,16,19)) }

if (d.dayOfWeek<6) {
    x = d.monthOfYear;
    if ( x>4 && x<12 ) {
        if (j(d,10,17)) r="On";
        if (k(d)) r=m
    } else if (x<5||x>10) {
        if (j(d,10,17)) r=m;
        if (k(d)) r="On"
    }
}
println r
Michael Easter
la source
2
Depuis Java 8, il y en a aussi java.time.*, qui est très similaire à Joda Time mais fait partie du JRE. Cela pourrait peut-être raccourcir un peu le code.
ntoskrnl
re: Java 8. excellent point
Michael Easter
Dans votre avant-dernier exemple '2014-01-05T08:08', le 5 janvier 2014 est un dimanche. Ainsi, il devrait être'Off'
BeetDemGuise
re: 5 janvier 2014. Tout à fait. Le code actuel est correct, mais l'exécution en sortie est incorrecte. Réparera.
Michael Easter
J'ai essayé java.time.*. a lamentablement échoué. L'analyseur est trop sacrément strict. Utilisation DateParserde nashorn (également partie du JRE8) qui est indulgente, et avec un peu de piratage abusif, même assez indulgente pour sauter les minutes et les secondes.
Mark Jeronimus
2

R, 243 204 caractères

b=strptime(scan(,""),"%Y-%m-%dT%H");i=function(x)as.integer(format(b,x));h=i("%H");d=i("%m%d");w=d>1100|d<430;f=ifelse;cat(c("Off","Mid","On")[f(i("%u")%in%5:6|h<7|h>19,1,f(h>11&h<17,f(w,2,3),f(w,3,2)))])

Indenté et commenté:

b=strptime(scan(,""),"%Y-%m-%dT%H") #Takes stdin and converts into POSIXct
i=function(x)as.integer(format(b,x)) #Format the POSIXct and convert it to integer
h=i("%H")      #Format to hours
d=i("%m%d")    #Format to Month/Day
w=d>1100|d<430 #True if winter time, false if summer
f=ifelse
cat(c("Off","Mid","On")[f(i("%u")%in%5:6|h<7|h>19, #If weekend or night
                          1,                       #Case 1
                          f(h>11&h<17,            #Else if mid-day
                             f(w,3,2),             #Case 2 in winter, case 3 in summer
                             f(w,2,3)))])          #else vice versa

Exemples:

> b=strptime(scan(,""),"%Y-%m-%dT%H");i=function(x)as.integer(format(b,x));h=i("%H");d=i("%m%d");w=d>1100|d<430;f=ifelse;cat(c("Off","Mid","On")[f(i("%u")%in%5:6|h<7|h>19,1,f(h>11&h<17,f(w,3,2),f(w,2,3)))])
1: 2014-08-26T15
2: 
Read 1 item
On
> b=strptime(scan(,""),"%Y-%m-%dT%H");i=function(x)as.integer(format(b,x));h=i("%H");d=i("%m%d");w=d>1100|d<430;f=ifelse;cat(c("Off","Mid","On")[f(i("%u")%in%5:6|h<7|h>19,1,f(h>11&h<17,f(w,3,2),f(w,2,3)))])
1: 2014-12-10T15
2: 
Read 1 item
Mid
> b=strptime(scan(,""),"%Y-%m-%dT%H");i=function(x)as.integer(format(b,x));h=i("%H");d=i("%m%d");w=d>1100|d<430;f=ifelse;cat(c("Off","Mid","On")[f(i("%u")%in%5:6|h<7|h>19,1,f(h>11&h<17,f(w,3,2),f(w,2,3)))])
1: 2014-08-26T23
2: 
Read 1 item
Off
plannapus
la source
1

Bash, 286

ceci est une réponse bash simple en utilisant le programme de date

d(){ date -d $1 +%$2; };D=$(echo $1|sed 's/\(T..\)$/\1:00/');H=$(d $D H);M=$(d $D m);if [ $(d $D u) -gt 5 ]||[ $H -lt 7 ]||[ $H -gt 18 ];then echo Off;exit;fi;if [ $M -gt 4 ]&&[ $M -lt 11 ];then I=On;O=Mid;else I=Mid;O=On;fi;if [ $H -gt 10 ]&&[ $H -lt 17 ];then echo $I;else echo $O;fi
Optokopper
la source
1

En voici un autre!

JavaScript, 175 171

function f(x){d=new Date(x.slice(0,10));t=x.slice(11,13),m=(x.slice(5,7)+1)%12;return(t<8||t>18||!(d.getUTCDay()%6)?'off':((t<11||t>17)?(m<5?'on':'mid'):(m<5?'mid':'on'))}

Non minifié:

function f(x) {
  d = new Date(x.slice(0, 10));
  t = x.slice(11, 13), m = (x.slice(5, 7) + 1) % 12;
  return (t < 8 || t > 18 || !(d.getUTCDay() % 6) ? 'off' : ((t < 11 || t > 17) ? (m < 5 ? 'on' : 'mid') : (m < 5 ? 'mid' : 'on'))
}

Fonctionne uniquement sur les interprètes où une chaîne de date ISO8601 peut être passée dans le Dateconstructeur.

CoffeeScript, 192 189

Étonnamment, il est plus long dans CoffeeScript car il n'y a pas d'opérateur ternaire dans ce langage (comme vous pouvez le voir sur mon JavaScript, je me suis beaucoup appuyé).

f=(x)->d=new Date(x.slice(0,10));t=x.slice(11,13);m=(x.slice(5,7)+1)%12;return'off'if(t<8||t>18||!(d.getUTCDay()%6));if(t<11||t>17)then(if m<5then'on'else'mid')else(if m<5then'mid'else'on')
rink.attendant.6
la source
0

ES6 - 146

Ceci est sous forme de fonction, utilise quelques hacks méchants.

let y,m,d,h,c=s=>[y,m,d,h]=s.split(/[T:-]/g).map(i=>+i),new Date(y,m,d).getDay()in{0:1,6:1}||h<20||8>h?'Off':['Mid','On'][(10>h&&h>16)^(m>5||m<8)]

Expliqué:

// These variables are declared outside of the function scope to save
// characters.
let y, // year
    m, // month
    d, // day
    h, // hour
    c = s => // c for check, called as c(isoString)
      [y, m, d, h] = // Assign to fields
        s.split(/[T:-]/g) // Split at delimiters
         .map(i => +i), // Convert all to numbers
                        // Comma used to keep it as a single statement.
      new Date(y, m, d).getDay() // Create Date to get day of week
        in {0:1, 6:1} // Check if it is good (0 = Sunday, 6 = Saturday). It
                      // is shorter to use an object literal than to
                      // do individual checks.
      ||
      h < 20 || 8 > h ? // h is between 7 and 19 (7pm)
       'Off' : // Return 'Off'
       ['Mid','On'][ // Two other outputs
        (10 > h && h > 16) ^ // Check if it is 11-16 (5pm)
        (m > 5 || m < 8)] // Invert that if the month is in summer/fall. Note
                          // that this returns a number, either 1 or 0. This
                          // is an ugly hack using the bitwise xor operator.
Isiah Meadows
la source
0

Python 3 - 352 caractères

import datetime as dt
t=input()
i=int
p=print
a='on'
b='mid'
c='off'
m=i(t[5:7])
h=i(t[11:13])
d=dt.date(i(t[0:4]),m,i(t[8:10])).weekday()
if 5==d or 6==d:p(c)
elif h>=19 and h<7:p(c)
elif m<=10 and m>=4:
 if h>=7 and h<11:p(b)
 if h>=11 and h<17:p(a)
 if h>=17 and h<19:p(b)
else:
 if h>=7 and h<11:p(a)
 if h>=11 and h<17:p(b)
 if h>=17 and h<19:p(a)
Beta Decay
la source
1
Vous devriez changer s=['high','mid','off']pour s=['on','mid','off']- non seulement cela enregistre 2 caractères, mais la spécification indique de sortir "on".
Sellyme
0

Java - 426 309/301? (voir les commentaires)

String z(String a){
    DateParser b=new DateParser(a);
    boolean c=b.parseEcmaDate();
    Integer[]d=b.getDateFields();
    GregorianCalendar e=new GregorianCalendar(d[0],d[1]-(c?0:1),d[2]);
    e.setTimeZone(new SimpleTimeZone(0,""));
    return(124>>e.get(7)&1)>0&d[3]>6&d[3]<19?
           d[3]>10&d[3]<17^(1008>>e.get(2)&1)>0?"Mid":"On":"Off";
}

Exemple de sortie:

2014-03-02T00   Off
2014-03-02T06   Off
2014-03-02T07   Off
2014-03-02T10   Off
2014-03-02T11   Off
2014-03-02T16   Off
2014-03-02T17   Off
2014-03-02T18   Off
2014-03-02T19   Off
2014-03-02T23   Off
2014-04-02T00   Off
2014-04-02T06   Off
2014-04-02T07   On
2014-04-02T10   On
2014-04-02T11   Mid
2014-04-02T16   Mid
2014-04-02T17   On
2014-04-02T18   On
2014-04-02T19   Off
2014-04-02T23   Off
2014-05-02T00   Off
2014-05-02T06   Off
2014-05-02T07   Mid
2014-05-02T10   Mid
2014-05-02T11   On
2014-05-02T16   On
2014-05-02T17   Mid
2014-05-02T18   Mid
2014-05-02T19   Off
2014-05-02T23   Off

J'ai utilisé la même astuce EXOR que la soumission Python. J'ai également utilisé un +comme une fonction OU, pour quand c'est weekend OR night.

Mon autre gros truc: les masques à mors.

Par exemple, pour voir si un nombre est compris entre 2 et 6 (du lundi au vendredi), créez d'abord un motif binaire où les valeurs intéressantes sont 1:

  6   2 
0b1111100 = 124

Ensuite, utilisez le décalage de bit pour obtenir le bit intéressant vers le LSB et extrayez-le:

(124 >> day_of_week) & 1

De même, j'ai fait des motifs binaires pendant des mois et des heures:

  9    4
0b1111110000 = 1008

      76          76
0b111110000000000001111111 = 16253055
0b000000011111100000000000 = 129024

Malheureusement, il s'avère tout simplement x>y&x<zplus court dans la plupart des cas, donc je ne l'ai pas utilisé à certains endroits.

Et enfin, un peu de piratage (très dépendant de l'implémentation) avec jdk.nashorn.internal.parser.DateParser: QuandparseEcmaDate() pas complètement une date (comme quand il lit l'heure et frappe la fin de la chaîne), il retourne false.

  • Quand elle se termine correctement, la date est stockée dans un Integer[] (ftw auto-unboxing), avec le mois fixé à base-0 (comme les autres classes Java).
  • Lorsqu'il retourne faux, il a avorté à mi-chemin et n'a pas effectué cette correction. Cependant, il met toujours tout ce qu'il a analysé dans le tableau, qui est facilement disponible. D'où le -(c?0:1).
Mark Jeronimus
la source
Je pense que l'utilisation .parse()pourrait aussi fonctionner (raser 8 caractères), mais je ne l'ai pas testé à fond avec différentes entrées. parseappelle en interne parseEcmaDateet s'il échoue, appelle parseLegacyDate. Ce dernier peut visser le tableau, mais cela ne s'est pas produit avec quelques cas que j'ai testés.
Mark Jeronimus
-1

Rien ne m'empêche d'entrer dans le mien, et il y en a d'autres de toute façon ici, donc ...

PHP 5.4+, 194

<?function f($x){$t=substr($x,11,2);$m=(substr($x,5,2)+1)%12;if($t<8||$t>18||(new DateTime(substr($x,0,10)))->format('N')>5)return'off';return($t<11||$t>17)?($m<5?'on':'mid'):($m<5?'mid':'on');}

Non minimisé et commenté:

<?
function f($x) {
  $t = substr($x,11,2); // hour
  $m = (substr($x,5,2) + 1) % 12; // month shifted up by 1

  if ($t < 8 || $t > 18 || (new DateTime(substr($x,0,10)))->format('N') > 5)
    return 'off'; // evenings and weekends

  return ($t < 11 || $t > 17)
    ? ($m < 5 ? 'on' : 'mid') // morning and mid-afternoon
    : ($m < 5 ? 'mid' : 'on'); // afternoon
}

Notez également que la date.timezonedirective dans php.ini doit être définie, sinon une exception sera levée.

rink.attendant.6
la source