Last active
February 19, 2016 06:38
-
-
Save jhthorsen/54ae539a6d6d9cb520f3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
use Mojolicious::Lite; | |
use List::Util 'reduce'; | |
use Time::Piece; | |
use Time::Seconds; | |
sub off { | |
return ( | |
'01-01' => 'Nyttårsdag', | |
'04-02' => 'Skjærtorsdag', | |
'04-03' => 'Langfredag', | |
'04-05' => '1. påskedag', | |
'04-06' => '2. påskedag', | |
'05-01' => 'Arbeidernes dag', | |
'05-14' => 'Kristi Himmelfartsdag', | |
'05-17' => 'Grunnlovsdag', | |
'05-24' => '1. pinsedag', | |
'05-25' => '2. pinsedag', | |
'12-25' => '1. juledag', | |
'12-26' => '2. juledag', | |
); | |
} | |
sub christmas { | |
my ($t, $off) = @_; | |
my $ft = $off->{_christmas_ft} ||= do { | |
my ($start) = grep { $off->{$_} and $off->{$_} eq '1. juledag' } keys %$off; | |
$start = Time::Piece->strptime("$off->{year}-$start", '%Y-%m-%d') - ONE_DAY; | |
[$start->epoch, ($start + 7 * ONE_DAY)->epoch]; | |
}; | |
return $t->epoch >= $ft->[0] && $t->epoch <= $ft->[1]; | |
} | |
sub easter { | |
my ($t, $off) = @_; | |
my $ft = $off->{_easter_ft} ||= do { | |
my ($end) = grep { $off->{$_} and $off->{$_} eq '2. påskedag' } keys %$off; | |
$end = Time::Piece->strptime("$off->{year}-$end", '%Y-%m-%d'); | |
[($end - 7 * ONE_DAY)->epoch, $end->epoch]; | |
}; | |
return $t->epoch >= $ft->[0] && $t->epoch <= $ft->[1]; | |
} | |
get '/' => sub { | |
my $c = shift; | |
my $end = $c->param('to') || localtime->ymd('-'); | |
my $year = $end =~ /(\d\d\d\d)/ ? $1 : localtime->year; | |
my $t = Time::Piece->strptime("${year}-01-01T00:00:00", '%Y-%m-%dT%H:%M:%S'); | |
my %off = off(); | |
my $days = 0; | |
$c->stash(today => localtime->ymd('-')); | |
map { $c->param($_ => 1) } qw( christmas easter weekends ) unless defined $c->param('vacation_days'); | |
$end = $end =~ /\d/ ? Time::Piece->strptime("${end}T23:59:59", '%Y-%m-%dT%H:%M:%S') : Time::Piece->new; | |
$off{holiday} = 0; | |
$off{year} = $year; | |
$off{vacation_days} = $c->param('vacation_days'); | |
$off{christmas} = $c->param('christmas') ? 0 : undef; | |
$off{easter} = $c->param('easter') ? 0 : undef; | |
$off{weekends} = $c->param('weekends') ? 0 : undef; | |
while (1) { | |
last if $t >= $end; | |
if ($off{$t->strftime('%m-%d')}) { | |
$off{holiday}++; | |
} | |
elsif (defined $off{weekends} and $t->day =~ /^(?:Sat|Sun)/) { | |
$off{weekends}++; | |
} | |
elsif (defined $off{easter} and easter($t, \%off)) { | |
$off{easter}++; | |
} | |
elsif (defined $off{christmas} and christmas($t, \%off)) { | |
$off{christmas}++; | |
} | |
} | |
continue { | |
$days++; | |
$t += ONE_DAY; | |
} | |
$off{total} = reduce { $a + $b } map { $off{$_} || 0 } qw( weekends easter christmas holiday vacation_days ); | |
$c->render(end => $end, days => $days, off => \%off, year => $year); | |
}, 'index'; | |
app->start; | |
__DATA__ | |
@@ index.html.ep | |
<html> | |
<head> | |
<title>Arbeidsdager <%= $year%></title> | |
%= stylesheet begin | |
@font-face { | |
font-family: 'Lato'; | |
font-style: normal; | |
font-weight: 400; | |
src: local('Lato Regular'), local('Lato-Regular'), url(https://fonts.gstatic.com/s/lato/v11/8qcEw_nrk_5HEcCpYdJu8BTbgVql8nDJpwnrE27mub0.woff2) format('woff2'); | |
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF; | |
} | |
@font-face { | |
font-family: 'Lato'; | |
font-style: normal; | |
font-weight: 400; | |
src: local('Lato Regular'), local('Lato-Regular'), url(https://fonts.gstatic.com/s/lato/v11/MDadn8DQ_3oT6kvnUq_2r_esZW2xOQ-xsNqO47m55DA.woff2) format('woff2'); | |
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; | |
} | |
body, input, td { | |
font-size: 16px; | |
font-family: Lato, sans-serif; | |
margin: 0; | |
padding: 0; | |
} | |
h1 { | |
font-size: 2.5em; | |
width: 90%; | |
margin: 1em auto; | |
} | |
table { | |
border-collapse: collapse; | |
width: 90%; | |
margin: 0 auto; | |
} | |
table th { | |
padding: 0.8em 0.8em; | |
font-size: 1.2em; | |
font-weight: bold; | |
text-align: left; | |
border-bottom: 2px solid #3ae; | |
} | |
table td { padding: 0.5em 1em; } | |
tfoot td { | |
padding: 1em 1em; | |
border-top: 2px solid #ccc; | |
border-bottom: 6px double #f55; | |
} | |
.text-field { | |
background: #ffffff; | |
border: 1px dashed #aaa; | |
padding: 5px 7px; | |
margin: -5px 0; | |
} | |
.text-field:focus { | |
outline: 1px dashed #f77; | |
outline-offset: 0; | |
border-color: #fff; | |
} | |
.btn { | |
background-color: #3ae; | |
font-family: Lato, Arial; | |
font-weight: bold; | |
color: #ffffff; | |
border: 1px solid #057fd0; | |
padding: 8px 24px; | |
outline: 0; | |
display: inline-block; | |
cursor: pointer; | |
text-decoration: none; | |
} | |
.container { | |
margin: 3em; | |
} | |
@media (max-width: 800px) { | |
table, h1 { width: 100%; margin: 1em 0; } | |
.container { margin: 1em 0.5em; }; | |
} | |
% end | |
</head> | |
<body> | |
<div class="container"> | |
<h1>Arbeidsdager i <%= $year %></h1> | |
%= form_for 'index', begin | |
<table> | |
<thead> | |
<tr> | |
<th> </th> | |
<th>Beskrivelse</th> | |
<th>Dager</th> | |
<th> </th> | |
</tr> | |
</thead> | |
<tbody> | |
<tr> | |
<td> </td> | |
<td><%= $year %>-01-01 til <%= text_field to => $today, size => 12, autocomplete => 'off', placeholder => $today, class => 'text-field' %></td> | |
<td><%= $days %></td> | |
<td> </td> | |
</tr> | |
<tr> | |
<td>-</td> | |
<td>Lør- og søndag</td> | |
<td><%= $off->{weekends} || 0 %></td> | |
<td><%= check_box weekends => 1, defined $off->{weekends} ? (checked => 'checked') : () %></td> | |
</tr> | |
<tr> | |
<td>-</td> | |
<td>Feriedager</td> | |
<td><%= text_field vacation_days => 0, size => 2, class => 'text-field', autocomplete => 'off' %></td> | |
<td> </td> | |
</tr> | |
<tr> | |
<td>-</td> | |
<td>Hellig- og høytidsdager</td> | |
<td><%= $off->{holiday} || 0 %></td> | |
<td> </td> | |
</tr> | |
<tr> | |
<td>-</td> | |
<td>Fri i påsken</td> | |
<td><%= $off->{easter} || 0 %></td> | |
<td><%= check_box easter => 1, defined $off->{easter} ? (checked => 'checked') : () %></td> | |
</tr> | |
<tr> | |
<td>-</td> | |
<td>Fri i julen</td> | |
<td><%= $off->{christmas} || 0 %></td> | |
<td><%= check_box christmas => 1, defined $off->{christmas} ? (checked => 'checked') : () %></td> | |
</tr> | |
</tbody> | |
<tfoot> | |
<tr style="border-top:1px solid #000;"> | |
<td>=</td> | |
<td>Arbeidsdager</td> | |
<td title="<%= 7.5 * ($days - $off->{total}) %> timer"><%= $days - $off->{total} %></td> | |
<td><%= submit_button 'Oppdater', class => "btn" %></td> | |
</tr> | |
</tfoot> | |
</table> | |
% end | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment