Skip to content

Instantly share code, notes, and snippets.

@behrad
Last active December 18, 2015 14:49
Show Gist options
  • Save behrad/5799941 to your computer and use it in GitHub Desktop.
Save behrad/5799941 to your computer and use it in GitHub Desktop.
Jalali Calendar Implementation
%% Copyright
-module(jalali).
-author("jrad <behradz@gmail.com>").
-define( G_DAYS_IN_MONTH, [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ] ).
-define( J_DAYS_IN_MONTH, [ 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 ] ).
%% API
-export([
gregorian_to_jalali/1,
jalali_to_gregorian/1]).
gregorian_to_jalali( {{Y,M,D}, {HH,MM,SS}} ) ->
{ gregorian_to_jalali( {Y,M,D} ), {HH,MM,SS} };
gregorian_to_jalali( {Y,M,D} ) ->
{ GY, GM, GD } = {Y - 1600, M - 1, D - 1},
G_DAY_NO__ = 365*GY+((GY+3) div 4)-((GY+99) div 100)+((GY+399) div 400),
G_DAY_NO_ = GD + G_DAY_NO__ + lists:sum( lists:sublist( ?G_DAYS_IN_MONTH, GM ) ),
G_DAY_NO = add_leap( G_DAY_NO_, GM, GY ),
J_DAY_NO = G_DAY_NO - 79,
J_NP = J_DAY_NO div 12053,
J_DAY_NO_ = J_DAY_NO rem 12053,
JY = 979 + 33*J_NP + 4 * (J_DAY_NO_ div 1461),
J_DAY_NO__ = J_DAY_NO_ rem 1461,
{J_DAY_NO___, JY_} = extra_years( J_DAY_NO__, JY ),
{ I, J_DAY } = for_loop( 0, ?J_DAYS_IN_MONTH, J_DAY_NO___ ),
{ JY_, I+1, J_DAY+1 }.
jalali_to_gregorian( {{Y,M,D}, {HH,MM,SS}} ) ->
{ jalali_to_gregorian( {Y,M,D} ), {HH,MM,SS} };
jalali_to_gregorian( {Y,M,D} ) ->
{ JY, JM, JD } = {Y - 979, M - 1, D - 1},
J_DAY_NO__ = 365*JY + (JY div 33)*8 + (((JY rem 33)+3) div 4),
J_DAY_NO_ = JD + J_DAY_NO__ + lists:sum( lists:sublist( ?J_DAYS_IN_MONTH, JM ) ),
G_DAY_NO = J_DAY_NO_ + 79,
GY_ = 1600 + 400 * (G_DAY_NO div 146097),
G_DAY_NO_ = G_DAY_NO rem 146097,
{G_DAY_NO__, Leap, GYY} = add_leap_j( G_DAY_NO_ ),
GY__ = GYY + GY_,
GY = GY__ + (4 * (G_DAY_NO__ div 1461)),
G_DAY_NO___ = G_DAY_NO__ rem 1461,
{G_DAY_NO2, Leap2, GY2} = check_leap_j( G_DAY_NO___, Leap, GY ),
{ I, GDN } = for_loop_j( Leap2, 0, ?G_DAYS_IN_MONTH, G_DAY_NO2, get_leap_value(0, Leap2) ),
{GY2, I+1, GDN+1 }.
check_leap_j( G_DAY_NO, _Leap, GY ) when G_DAY_NO >= 366 ->
G_DAY_NO_ = G_DAY_NO-1,
{G_DAY_NO_ rem 365, 0, GY+(G_DAY_NO_ div 365) };
check_leap_j( G_DAY_NO, Leap, GY ) ->
{G_DAY_NO, Leap, GY }.
add_leap_j( G_DAY_NO ) when G_DAY_NO >= 36525 ->
G_DAY_NO_ = G_DAY_NO-1,
GY = 100 * (G_DAY_NO_ div 36524),
G_DAY_NO__ = G_DAY_NO_ rem 36524,
if
G_DAY_NO__ >= 365 -> {G_DAY_NO__+1, 1, GY};
G_DAY_NO__ < 365 -> {G_DAY_NO__, 0, GY}
end;
add_leap_j( G_DAY_NO ) ->
{G_DAY_NO,1,0}.
get_leap_value( I, Leap ) when (I==1) and (Leap==1) ->
1;
get_leap_value( _I, _Leap ) ->
0.
for_loop_j( Leap, I, [DAY_NO|Rest], G_DAY_NO, LV ) when (G_DAY_NO >= (DAY_NO+LV)) ->
for_loop_j( Leap, I+1, Rest, G_DAY_NO - (DAY_NO+get_leap_value(I, Leap)), get_leap_value(I, Leap) );
for_loop_j( _Leap, I, _, G_DAY_NO, _LV ) ->
{I, G_DAY_NO }.
for_loop( I, [DAY_NO|Rest], J_DAY_NO ) when (I < 11) and (J_DAY_NO >= DAY_NO) ->
for_loop( I+1, Rest, J_DAY_NO - DAY_NO );
for_loop( I, _, J_DAY_NO ) ->
{I, J_DAY_NO }.
add_leap( G_DAY, GM, GY ) when (GM>1) and ((GY rem 4 == 0) and (GY rem 100 /= 0) ) or (GY rem 400 == 0) ->
G_DAY + 1;
add_leap( G_DAY, _GM, _GY ) ->
G_DAY.
extra_years( J_DAY_NO, JY ) when J_DAY_NO >= 366 ->
J_DAY = J_DAY_NO-1,
{ J_DAY rem 365, JY + (J_DAY div 365) };
extra_years( J_DAY_NO, JY ) when J_DAY_NO < 366 ->
{ J_DAY_NO, JY }.
/* jalali.js Gregorian to Jalali and inverse date convertor
* Copyright (C) 2001 Roozbeh Pournader <roozbeh@sharif.edu>
* Copyright (C) 2001 Mohammad Toossi <mohammad@bamdad.org>
* Copyright (C) 2003,2008 Behdad Esfahbod <js@behdad.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You can receive a copy of GNU Lesser General Public License at the
* World Wide Web address <http://www.gnu.org/licenses/lgpl.html>.
*
* For licensing issues, contact The FarsiWeb Project Group,
* Computing Center, Sharif University of Technology,
* PO Box 11365-8515, Tehran, Iran, or contact us the
* email address <FWPG@sharif.edu>.
*/
/* Changes:
*
* 2008-Jul-32:
* Use a remainder() function to fix conversion of ancient dates
* (before 1600 gregorian). Reported by Shamim Rezaei.
*
* 2003-Mar-29:
* Ported to javascript by Behdad Esfahbod
*
* 2001-Sep-21:
* Fixed a bug with "30 Esfand" dates, reported by Mahmoud Ghandi
*
* 2001-Sep-20:
* First LGPL release, with both sides of conversions
*/
g_days_in_month = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
j_days_in_month = new Array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
function div(a,b) {
return Math.floor(a/b);
}
function remainder(a,b) {
return a - div(a,b)*b;
}
function gregorian_to_jalali(g /* array containing year, month, day*/ )
{
var gy, gm, gd;
var jy, jm, jd;
var g_day_no, j_day_no;
var j_np;
var i;
gy = g[0]-1600;
gm = g[1]-1;
gd = g[2]-1;
g_day_no = 365*gy+div((gy+3),4)-div((gy+99),100)+div((gy+399),400);
for (i=0;i<gm;++i)
g_day_no += g_days_in_month[i];
if (gm>1 && ((gy%4==0 && gy%100!=0) || (gy%400==0)))
/* leap and after Feb */
++g_day_no;
g_day_no += gd;
j_day_no = g_day_no-79;
j_np = div(j_day_no, 12053);
j_day_no = remainder (j_day_no, 12053);
jy = 979+33*j_np+4*div(j_day_no,1461);
j_day_no = remainder (j_day_no, 1461);
if (j_day_no >= 366) {
jy += div((j_day_no-1),365);
j_day_no = remainder ((j_day_no-1), 365);
}
for (i = 0; i < 11 && j_day_no >= j_days_in_month[i]; ++i) {
j_day_no -= j_days_in_month[i];
}
jm = i+1;
jd = j_day_no+1;
return new Array(jy, jm, jd);
}
function jalali_to_gregorian(j /* array containing year, month, day*/ )
{
var gy, gm, gd;
var jy, jm, jd;
var g_day_no, j_day_no;
var leap;
var i;
jy = j[0]-979;
jm = j[1]-1;
jd = j[2]-1;
j_day_no = 365*jy + div(jy,33)*8 + div((remainder (jy, 33)+3),4);
for (i=0; i < jm; ++i)
j_day_no += j_days_in_month[i];
j_day_no += jd;
g_day_no = j_day_no+79;
gy = 1600 + 400*div(g_day_no,146097); /* 146097 = 365*400 + 400/4 - 400/100 + 400/400 */
g_day_no = remainder (g_day_no, 146097);
leap = 1;
if (g_day_no >= 36525) /* 36525 = 365*100 + 100/4 */
{
g_day_no--;
gy += 100*div(g_day_no,36524); /* 36524 = 365*100 + 100/4 - 100/100 */
g_day_no = remainder (g_day_no, 36524);
if (g_day_no >= 365)
g_day_no++;
else
leap = 0;
}
gy += 4*div(g_day_no,1461); /* 1461 = 365*4 + 4/4 */
g_day_no = remainder (g_day_no, 1461);
if (g_day_no >= 366) {
leap = 0;
g_day_no--;
gy += div(g_day_no, 365);
g_day_no = remainder (g_day_no, 365);
}
for (i = 0; g_day_no >= g_days_in_month[i] + (i == 1 && leap); i++)
g_day_no -= g_days_in_month[i] + (i == 1 && leap);
gm = i+1;
gd = g_day_no+1;
return new Array(gy, gm, gd);
}
function jalali_today() {
Today = new Date();
j = gregorian_to_jalali(new Array(
Today.getFullYear(),
Today.getMonth()+1,
Today.getDate()
));
return j[2]+"/"+j[1]+"/"+j[0];
}
<?php
/* This file is part of:
* Jalali, a Gregorian to Jalali and inverse date convertor
* Copyright (C) 2001, 2002 Roozbeh Pournader <roozbeh@farsiweb.info>
* Copyright (C) 2001, 2002 Mohammad Toossi <mohammad@bamdad.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You can receive a copy of GNU Lesser General Public License at the
* World Wide Web address <http://www.gnu.org/licenses/lgpl.html>.
*
* For licensing issues, contact The FarsiWeb Project Group,
* Computing Center, Sharif University of Technology,
* PO Box 11365-8515, Tehran, Iran, or contact us the
* email address <FWPG@sharif.edu>.
*/
/* Changes:
*
* 2002-Feb-19:
* Added PHP header and tailer
* 2002-Jan-28:
* First LGPL release
*/
$g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
$j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
$j_month_name = array("", "Farvardin", "Ordibehesht", "Khordad", "Tir",
"Mordad", "Shahrivar", "Mehr", "Aban", "Azar",
"Dey", "Bahman", "Esfand");
function div($a, $b)
{
return (int) ($a / $b);
}
function gregorian_to_jalali($g_y, $g_m, $g_d)
{
global $g_days_in_month;
global $j_days_in_month;
$gy = $g_y-1600;
$gm = $g_m-1;
$gd = $g_d-1;
$g_day_no = 365*$gy+div($gy+3,4)-div($gy+99,100)+div($gy+399,400);
for ($i=0; $i < $gm; ++$i)
$g_day_no += $g_days_in_month[$i];
if ($gm>1 && (($gy%4==0 && $gy%100!=0) || ($gy%400==0)))
/* leap and after Feb */
++$g_day_no;
$g_day_no += $gd;
$j_day_no = $g_day_no-79;
$j_np = div($j_day_no, 12053);
$j_day_no %= 12053;
$jy = 979+33*$j_np+4*div($j_day_no,1461);
$j_day_no %= 1461;
if ($j_day_no >= 366) {
$jy += div($j_day_no-1, 365);
$j_day_no = ($j_day_no-1)%365;
}
for ($i = 0; $i < 11 && $j_day_no >= $j_days_in_month[$i]; ++$i) {
$j_day_no -= $j_days_in_month[$i];
}
$jm = $i+1;
$jd = $j_day_no+1;
return array($jy, $jm, $jd);
}
function farsinum($str)
{
if (strlen($str) == 1)
$str = "0".$str;
$out = "";
for ($i = 0; $i < strlen($str); ++$i) {
$c = substr($str, $i, 1);
$out .= pack("C*", 0xDB, 0xB0 + $c);
}
return $out;
}
function date_format_html($datestamp)
{
$tzoffset = 0;
list($date,$time) = explode(" ",$datestamp);
list($year,$month,$day) = explode("-",$date);
list($hour,$minute,$second) = explode(":",$time);
$hour = $hour + $tzoffset;
list($jyear, $jmonth, $jday) = gregorian_to_jalali($year,$month,$day);
$sDate = farsinum($jyear - 1300)."/".farsinum($jmonth)."/".farsinum($jday)
."&nbsp;&nbsp;".farsinum($hour).":".farsinum($minute);
return "<span lang='fa' dir='rtl'>" . $sDate . "</span>";
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment