دست‌نویس

تاریخ شمسی در گوگل شیت: تابع آماده‌ی SHAMSI با Apps Script

· ۶ دقیقه مطالعه · نویسنده: تیم دست‌نویس

خلاصه: گوگل شیت به‌طور پیش‌فرض تابعی برای نمایش تاریخ شمسی ندارد، ولی با چند خط Apps Script می‌توانید تابع =SHAMSI(A2) را اضافه کنید. کد این مقاله میلادی را به شمسی و برعکس تبدیل می‌کند و روی همه‌ی روزهای ۲۰۱۰ تا ۲۰۵۰ میلادی با الگوریتم تقویم دست‌نویس مقایسه شده است.

جواب کوتاه

تابع سفارشی (Custom Function) در Apps Script همان‌طور کار می‌کند که تابع‌های داخلی؛ فقط یک‌بار کدش را در فایل اضافه می‌کنید. بعد از آن =SHAMSI(A2) تاریخ میلادی سلول A2 را به شکل 1405/07/25 برمی‌گرداند و =FROM_SHAMSI(1405;7;25) تاریخ شمسی را به میلادی تبدیل می‌کند.

نصب در شش گام

  • فایل Google Sheets را باز کنید و از منوی «افزونه‌ها» (Extensions) گزینه‌ی «Apps Script» را بزنید.
  • کد پیش‌فرض را پاک کنید و کد بخش بعد را بچسبانید.
  • ذخیره کنید (Ctrl+S). اگر پروژه نام می‌خواهد، هر نامی بدهید.
  • به شیت برگردید. در یک سلول =SHAMSI(A2) بنویسید (A2 باید یک تاریخ واقعی باشد، نه متن).
  • برای تبدیل برعکس =FROM_SHAMSI(1405;7;25) را بنویسید. اگر فایل شما با ویرگول جدا می‌کند، =FROM_SHAMSI(1405,7,25) بنویسید.
  • سلولِ FROM_SHAMSI را از «قالب ← عدد ← تاریخ» به قالب تاریخ ببرید تا عدد خام نشان داده نشود.

کد کامل

/**
 * Shamsi (Jalali) dates in Google Sheets
 *   =SHAMSI(A2)                -> 1405/07/25
 *   =SHAMSI_YMD(A2)            -> three cells: year, month, day (numbers)
 *   =FROM_SHAMSI(1405; 7; 25)  -> Gregorian date (format the cell as Date)
 */
function SHAMSI(date) {
  var p = shamsiParts_(date);
  return p ? p.y + '/' + ('0' + p.m).slice(-2) + '/' + ('0' + p.d).slice(-2) : '';
}

function SHAMSI_YMD(date) {
  var p = shamsiParts_(date);
  return p ? [[+p.y, +p.m, +p.d]] : '';
}

function FROM_SHAMSI(y, m, d) {
  y = +y; m = +m; d = +d;
  if (!(y > 0 && m >= 1 && m <= 12 && d >= 1 && d <= 31)) return 'تاریخ نامعتبر';
  var day = 86400000;
  var t = Date.UTC(y + 621, 2, 21, 12) + ((m <= 6 ? (m - 1) * 31 : 186 + (m - 7) * 30) + d - 1) * day;
  for (var i = 0; i < 6; i++) {
    var p = persian_(new Date(t));
    var diff = (p.y - y) * 372 + (p.m - m) * 31 + (p.d - d);
    if (diff === 0) {
      var tz = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
      return Utilities.parseDate(Utilities.formatDate(new Date(t), 'UTC', 'yyyy-MM-dd'), tz, 'yyyy-MM-dd');
    }
    t -= (diff > 0 ? 1 : -1) * day;
  }
  return 'تاریخ نامعتبر';
}

// Shamsi year/month/day of a cell date (the day is read in the spreadsheet time zone)
function shamsiParts_(date) {
  if (date === '' || date === null || date === undefined) return null;
  if (!(date instanceof Date)) date = new Date(date);
  if (isNaN(date.getTime())) return null;
  var tz = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
  var g = Utilities.formatDate(date, tz, 'yyyy-MM-dd').split('-');
  return persian_(new Date(Date.UTC(+g[0], +g[1] - 1, +g[2], 12)));
}

function persian_(noonUtc) {
  var f = new Intl.DateTimeFormat('en-US-u-ca-persian-nu-latn', { timeZone: 'UTC', year: 'numeric', month: '2-digit', day: '2-digit' });
  var o = {};
  f.formatToParts(noonUtc).forEach(function (x) { o[x.type] = x.value; });
  return { y: +o.year, m: +o.month, d: +o.day };
}

این کد تاریخ را در منطقه‌ی زمانی خود فایل می‌خواند (از «فایل ← تنظیمات» قابل‌دیدن است)؛ پس برای فایلی با منطقه‌ی زمانی تهران، تاریخ نیمه‌شب سلول به روز درست تبدیل می‌شود.

نمونه‌ها

  • سلول با تاریخ ۲۰۲۶-۱۰-۱۷: =SHAMSI(A2) می‌دهد 1405/07/25.
  • =SHAMSI_YMD(A2) سه خانه‌ی کنار هم می‌دهد: ۱۴۰۵، ۷ و ۲۵ (برای ساخت گزارش ماهانه یا فیلتر بر اساس سال).
  • =FROM_SHAMSI(1405;7;25) می‌دهد ۲۰۲۶-۱۰-۱۷.
  • =FROM_SHAMSI(1403;12;30) (۳۰ اسفند سال کبیسه) می‌دهد ۲۰۲۵-۰۳-۲۰ و =FROM_SHAMSI(1404;12;30) پیام «تاریخ نامعتبر» می‌دهد، چون ۱۴۰۴ کبیسه نیست.

دقت و محدودیت‌ها

هسته‌ی تبدیل از قالب‌بندی تقویم persian در Intl استفاده می‌کند. ما خروجی همین تابع را برای همه‌ی ۱۴٬۹۷۵ روز از ۲۰۱۰ تا ۲۰۵۰ میلادی با الگوریتم تقویم دست‌نویس مقایسه کردیم و تفاوتی نبود؛ رفت‌وبرگشت تبدیل (میلادی ← شمسی ← میلادی) هم برای همه‌ی این روزها و در سه منطقه‌ی زمانی درست بود. این مقایسه با شبیه‌ساز سه فراخوانی Sheets (Utilities.formatDate، Utilities.parseDate و getSpreadsheetTimeZone) انجام شده، نه داخل خود Google Sheets؛ پس چند تاریخ را در فایل خودتان دستی بسنجید.

  • ورودی باید تاریخ واقعی باشد. متنی مثل "1405/07/25" در سلول تاریخ نیست و تابع خالی برمی‌گرداند.
  • برای اسناد رسمی همیشه تاریخ ثبت‌شده در سند معیار است؛ تقویم رسمی ایران بر پایه‌ی محاسبه‌ی نجومی است و برای سال‌های خیلی دور ممکن است یک روز فرق کند.
  • تابع‌های سفارشی روی هزار‌ها سلول کند می‌شوند؛ برای جدول‌های بزرگ یک بار تبدیل کنید و «کپی ← چسباندن فقط مقدار» بزنید.
  • اگر #NAME? دیدید، یعنی کد ذخیره نشده یا نام تابع غلط است؛ اگر پروژه‌ی قدیمی با موتور Rhino دارید، در «تنظیمات پروژه» موتور V8 را فعال کنید.

راه‌های دیگر

اگر به کد نیاز ندارید و فقط چند تاریخ دارید، ابزار تبدیل تاریخ سریع‌تر است. مرور راه‌های رایج در اکسل و گوگل‌شیت و خطای فرمول‌های «۶۲۱ سال و ۷۹ روز» در تبدیل تاریخ شمسی در اکسل و گوگل شیت آمده است.

در دست‌نویس

در «جدول‌ها»ی دست‌نویس لازم نیست کدی بنویسید: توابع SHAMSI، SHAMSI_YEAR، SHAMSI_MONTH، SHAMSI_DAY، SHAMSI_MONTH_NAME، FROM_SHAMSI و SHAMSI_PARSE از قبل هستند و روی همان الگوریتم دقیق تقویم اپ کار می‌کنند؛ مثلاً =SHAMSI(TODAY()) تاریخ امروز را شمسی می‌دهد. جدول‌های دست‌نویس فایل xlsx را مستقیم باز نمی‌کنند؛ از CSV وارد کنید.

پرسش‌های پرتکرار

چرا در گوگل شیت #NAME? می‌آید؟

معمولاً کد Apps Script ذخیره نشده یا نام تابع غلط نوشته شده است. کد را دوباره ذخیره کنید و مطمئن شوید پروژه با موتور V8 اجرا می‌شود.

جداکننده‌ی آرگومان ; است یا ,؟

بسته به تنظیمات منطقه‌ی فایل فرق می‌کند. اگر با نقطه‌ویرگول خطا گرفتید ویرگول را امتحان کنید و برعکس.

تاریخ شمسی را می‌شود به‌صورت خودکار قالب‌بندی کرد؟

خروجی SHAMSI متن است (مثل 1405/07/25) و برای نمایش کافی است. برای محاسبه از SHAMSI_YMD استفاده کنید که سال، ماه و روز را عدد جدا می‌دهد.

این مقاله جنبه‌ی آموزشی و عمومی دارد و جای توصیه‌ی پزشکی، حقوقی، مالی یا مالیاتی را نمی‌گیرد. نام و ویژگی سرویس‌های دیگر ممکن است عوض شده باشد؛ از سایت رسمی‌شان بررسی کنید. سلب مسئولیت

مقاله‌های دیگر

نظرها

هنوز نظری ثبت نشده. اولین نفر باشید.

نظر یا پرسش خود را بنویسید

نظرها پیش از نمایش بررسی می‌شوند. لینک و تبلیغ منتشر نمی‌شود.