From 80629bf338766ef92cb365f0970a011cf7b08b07 Mon Sep 17 00:00:00 2001 From: Patrizio Bekerle Date: Wed, 25 Jul 2018 13:01:09 +0200 Subject: [PATCH] added script solar-calendar-integration --- solar-calendar-integration/info.json | 10 + solar-calendar-integration/jalaali.js | 238 ++++++++++++++++++ .../solar-calendar-integration.qml | 35 +++ 3 files changed, 283 insertions(+) create mode 100644 solar-calendar-integration/info.json create mode 100644 solar-calendar-integration/jalaali.js create mode 100644 solar-calendar-integration/solar-calendar-integration.qml diff --git a/solar-calendar-integration/info.json b/solar-calendar-integration/info.json new file mode 100644 index 0000000..92a7727 --- /dev/null +++ b/solar-calendar-integration/info.json @@ -0,0 +1,10 @@ +{ + "name": "Solar (Jalaali) calendar integration", + "identifier": "solar-calendar-integration", + "script": "solar-calendar-integration.qml", + "resources": ["jalaali.js"], + "authors": ["@pbek"], + "version": "1.0.0", + "minAppVersion": "18.07.0", + "description" : "This script attempts to integrate the solar (Jalaali) calendar into QOwnNotes. It currently supports creating a headline for new notes with the current Jalaali date and time." +} diff --git a/solar-calendar-integration/jalaali.js b/solar-calendar-integration/jalaali.js new file mode 100644 index 0000000..a76ac84 --- /dev/null +++ b/solar-calendar-integration/jalaali.js @@ -0,0 +1,238 @@ + +/* + Converts a Gregorian date to Jalaali. +*/ +function toJalaali(gy, gm, gd) { + if (Object.prototype.toString.call(gy) === '[object Date]') { + gd = gy.getDate() + gm = gy.getMonth() + 1 + gy = gy.getFullYear() + } + return d2j(g2d(gy, gm, gd)) +} + +/* + Converts a Jalaali date to Gregorian. +*/ +function toGregorian(jy, jm, jd) { + return d2g(j2d(jy, jm, jd)) +} + +/* + Checks whether a Jalaali date is valid or not. +*/ +function isValidJalaaliDate(jy, jm, jd) { + return jy >= -61 && jy <= 3177 && + jm >= 1 && jm <= 12 && + jd >= 1 && jd <= jalaaliMonthLength(jy, jm) +} + +/* + Is this a leap year or not? +*/ +function isLeapJalaaliYear(jy) { + return jalCal(jy).leap === 0 +} + +/* + Number of days in a given month in a Jalaali year. +*/ +function jalaaliMonthLength(jy, jm) { + if (jm <= 6) return 31 + if (jm <= 11) return 30 + if (isLeapJalaaliYear(jy)) return 30 + return 29 +} + +/* + This function determines if the Jalaali (Persian) year is + leap (366-day long) or is the common year (365 days), and + finds the day in March (Gregorian calendar) of the first + day of the Jalaali year (jy). + + @param jy Jalaali calendar year (-61 to 3177) + @return + leap: number of years since the last leap year (0 to 4) + gy: Gregorian year of the beginning of Jalaali year + march: the March day of Farvardin the 1st (1st day of jy) + @see: http://www.astro.uni.torun.pl/~kb/Papers/EMP/PersianC-EMP.htm + @see: http://www.fourmilab.ch/documents/calendar/ +*/ +function jalCal(jy) { + // Jalaali years starting the 33-year rule. + var breaks = [ -61, 9, 38, 199, 426, 686, 756, 818, 1111, 1181, 1210 + , 1635, 2060, 2097, 2192, 2262, 2324, 2394, 2456, 3178 + ] + , bl = breaks.length + , gy = jy + 621 + , leapJ = -14 + , jp = breaks[0] + , jm + , jump + , leap + , leapG + , march + , n + , i + + if (jy < jp || jy >= breaks[bl - 1]) + throw new Error('Invalid Jalaali year ' + jy) + + // Find the limiting years for the Jalaali year jy. + for (i = 1; i < bl; i += 1) { + jm = breaks[i] + jump = jm - jp + if (jy < jm) + break + leapJ = leapJ + div(jump, 33) * 8 + div(mod(jump, 33), 4) + jp = jm + } + n = jy - jp + + // Find the number of leap years from AD 621 to the beginning + // of the current Jalaali year in the Persian calendar. + leapJ = leapJ + div(n, 33) * 8 + div(mod(n, 33) + 3, 4) + if (mod(jump, 33) === 4 && jump - n === 4) + leapJ += 1 + + // And the same in the Gregorian calendar (until the year gy). + leapG = div(gy, 4) - div((div(gy, 100) + 1) * 3, 4) - 150 + + // Determine the Gregorian date of Farvardin the 1st. + march = 20 + leapJ - leapG + + // Find how many years have passed since the last leap year. + if (jump - n < 6) + n = n - jump + div(jump + 4, 33) * 33 + leap = mod(mod(n + 1, 33) - 1, 4) + if (leap === -1) { + leap = 4 + } + + return { leap: leap + , gy: gy + , march: march + } +} + +/* + Converts a date of the Jalaali calendar to the Julian Day number. + + @param jy Jalaali year (1 to 3100) + @param jm Jalaali month (1 to 12) + @param jd Jalaali day (1 to 29/31) + @return Julian Day number +*/ +function j2d(jy, jm, jd) { + var r = jalCal(jy) + return g2d(r.gy, 3, r.march) + (jm - 1) * 31 - div(jm, 7) * (jm - 7) + jd - 1 +} + +/* + Converts the Julian Day number to a date in the Jalaali calendar. + + @param jdn Julian Day number + @return + jy: Jalaali year (1 to 3100) + jm: Jalaali month (1 to 12) + jd: Jalaali day (1 to 29/31) +*/ +function d2j(jdn) { + var gy = d2g(jdn).gy // Calculate Gregorian year (gy). + , jy = gy - 621 + , r = jalCal(jy) + , jdn1f = g2d(gy, 3, r.march) + , jd + , jm + , k + + // Find number of days that passed since 1 Farvardin. + k = jdn - jdn1f + if (k >= 0) { + if (k <= 185) { + // The first 6 months. + jm = 1 + div(k, 31) + jd = mod(k, 31) + 1 + return { jy: jy + , jm: jm + , jd: jd + } + } else { + // The remaining months. + k -= 186 + } + } else { + // Previous Jalaali year. + jy -= 1 + k += 179 + if (r.leap === 1) + k += 1 + } + jm = 7 + div(k, 30) + jd = mod(k, 30) + 1 + return { jy: jy + , jm: jm + , jd: jd + } +} + +/* + Calculates the Julian Day number from Gregorian or Julian + calendar dates. This integer number corresponds to the noon of + the date (i.e. 12 hours of Universal Time). + The procedure was tested to be good since 1 March, -100100 (of both + calendars) up to a few million years into the future. + + @param gy Calendar year (years BC numbered 0, -1, -2, ...) + @param gm Calendar month (1 to 12) + @param gd Calendar day of the month (1 to 28/29/30/31) + @return Julian Day number +*/ +function g2d(gy, gm, gd) { + var d = div((gy + div(gm - 8, 6) + 100100) * 1461, 4) + + div(153 * mod(gm + 9, 12) + 2, 5) + + gd - 34840408 + d = d - div(div(gy + 100100 + div(gm - 8, 6), 100) * 3, 4) + 752 + return d +} + +/* + Calculates Gregorian and Julian calendar dates from the Julian Day number + (jdn) for the period since jdn=-34839655 (i.e. the year -100100 of both + calendars) to some millions years ahead of the present. + + @param jdn Julian Day number + @return + gy: Calendar year (years BC numbered 0, -1, -2, ...) + gm: Calendar month (1 to 12) + gd: Calendar day of the month M (1 to 28/29/30/31) +*/ +function d2g(jdn) { + var j + , i + , gd + , gm + , gy + j = 4 * jdn + 139361631 + j = j + div(div(4 * jdn + 183187720, 146097) * 3, 4) * 4 - 3908 + i = div(mod(j, 1461), 4) * 5 + 308 + gd = div(mod(i, 153), 5) + 1 + gm = mod(div(i, 153), 12) + 1 + gy = div(j, 1461) - 100100 + div(8 - gm, 6) + return { gy: gy + , gm: gm + , gd: gd + } +} + +/* + Utility helper functions. +*/ + +function div(a, b) { + return ~~(a / b) +} + +function mod(a, b) { + return a - ~~(a / b) * b +} diff --git a/solar-calendar-integration/solar-calendar-integration.qml b/solar-calendar-integration/solar-calendar-integration.qml new file mode 100644 index 0000000..5cabd63 --- /dev/null +++ b/solar-calendar-integration/solar-calendar-integration.qml @@ -0,0 +1,35 @@ +import QtQml 2.0 +import QOwnNotesTypes 1.0 + +// see: https://github.com/jalaali/jalaali-js +import "jalaali.js" as Jalaali + +QtObject { + /** + * Set a headline for new notes with the current Jalaali date and time + */ + function handleNewNoteHeadlineHook(headline) { + const date = new Date(); + + // { jy: 1395, jm: 1, jd: 23 } + const jalaaliDate = Jalaali.toJalaali(date); + + var text = "Note " + jalaaliDate.jy + "-" + pad(jalaaliDate.jm, 2) + "-" + pad(jalaaliDate.jd, 2) + + " " + pad(date.getHours(), 2) + "." + pad(date.getMinutes(), 2) + "." + pad(date.getSeconds(), 2); + + var underline = "\n"; + + // add the underline + for (var i = 0; i < (text.length - 1); i++) { + underline += "="; + } + + return text + underline; + } + + function pad(num, size) { + var s = num+""; + while (s.length < size) s = "0" + s; + return s; + } +}