قالببندی زمان
زمان در یک رابط کاربری به سه شکل گوناگون ظاهر میشود، و درهم آمیختن آنها سرچشمهٔ همیشگی سردرگمی است. ranuts برای هر کدام تابعی جداگانه دارد:
| پرسشی که خواننده دارد | تابع | نمونهٔ خروجی |
|---|---|---|
| این دقیقاً کِی رخ داده است؟ | formatDate | 2026-07-25 14:05:09 |
| این چقدر طول میکشد؟ | formatDuration | 01:01:01 |
| چند وقت پیش بوده است؟ | formatRelative | 3 days ago، 5m |
formatDuration
شمار ثانیههای سپریشده را به شکل ساعتِ جداشده با دونقطه درمیآورد؛ همان شکلی که یک پخشکننده برای نشانگر پخش به کار میبرد: mm:ss که از یک ساعت که بگذرد به hh:mm:ss گشوده میشود.
پارامترها
| پارامتر | توضیح | نوع | پیشفرض |
|---|---|---|---|
seconds | ثانیههای سپریشده؛ مقدارهای منفی به ۰ چسبانده میشوند | number | الزامی |
Returns
string: خودِ مدت، یا '' اگر ورودی عددی متناهی نباشد.
import { formatDuration } from 'ranuts/utils';
formatDuration(0); // '00:00'
formatDuration(65); // '01:05'
formatDuration(3661); // '01:01:01'
formatDuration(NaN); // ''بازگرداندن رشتهٔ تهی در برابر NaN عمدی است: پخشکننده پیش از بارگیری فراداده سراغ video.duration میرود و NaN میگیرد، و آنجا یک برچسب خالی بهتر از NaN:NaN خوانده میشود.
نامش عوض شد
این تابع پیشتر timeFormat نام داشت. آن نام همچنان بهعنوان نامی منسوخ باقی است و رفتارش هم دقیقاً همان است، اما هیچ نشانی نمیداد که کدامیک از آن سه قالب زمان را میسازد.
formatRelative
یک لحظه را نسبت به لحظهای دیگر توصیف میکند: «۳ روز پیش»، «۲ ساعت دیگر».
بومیسازی به Intl.RelativeTimeFormat خودِ بستر سپرده میشود که از ۲۰۲۰ در همهٔ مرورگرهای مهم هست و قاعدههای جمع و صرف هر زبان را از پیش میداند. formatRelative تنها همان بخشی را میآورد که Intl عمداً کنار گذاشته است: اینکه فاصله را با کدام یکا بیان کنیم.
مانند خودِ Intl تنها یک یکا گزارش میکند: فاصلهٔ ۳ روز و ۶ ساعت میشود «۳ روز پیش»، و هرگز «۳ روز و ۶ ساعت پیش» نمیشود.
پارامترها
| پارامتر | توضیح | نوع | پیشفرض |
|---|---|---|---|
value | لحظهای که میخواهی توصیف شود | number | string | Date | الزامی |
options | پایینتر ببین | FormatRelativeOptions | {} |
| گزینه | توضیح | نوع | پیشفرض |
|---|---|---|---|
now | آنچه فاصله نسبت به آن سنجیده میشود | number | string | Date | زمان کنونی |
locale | برچسب یا برچسبهای BCP 47؛ سبک compact نادیدهشان میگیرد | string | string[] | زبان محیط اجرا |
style | 'long' | 'short' | 'narrow' | 'compact' | RelativeStyle | 'long' |
numeric | با 'auto' تعبیرهایی مانند yesterday جایگزین میشوند؛ با 'always' عددها سر جایشان میمانند | 'always' | 'auto' | 'auto' |
Returns
string — همان توصیف، یا '' هرگاه یکی از دو سر قابل خواندن نباشد.
import { formatRelative } from 'ranuts/utils';
const twoHoursAgo = Date.now() - 2 * 3600_000;
formatRelative(twoHoursAgo); // '2 hours ago'
formatRelative(twoHoursAgo, { style: 'short' }); // '2 hr. ago'
formatRelative(twoHoursAgo, { locale: 'zh-CN' }); // '2 小时前'
formatRelative(Date.now() + 60_000); // 'in 1 minute'
formatRelative(Date.now() - 86_400_000); // 'yesterday'
formatRelative(Date.now() - 86_400_000, { numeric: 'always' }); // '1 day ago'سبک compact
compact همان شکل فشردهٔ نشانگونه است که کنار آیتمهای یک خوراک یا فهرست دیده میشود:
formatRelative(Date.now() - 30_000, { style: 'compact' }); // '30s'
formatRelative(Date.now() - 5 * 60_000, { style: 'compact' }); // '5m'
formatRelative(Date.now() - 3 * 3600_000, { style: 'compact' }); // '3h'
formatRelative(Date.now() - 2 * 86_400_000, { style: 'compact' }); // '2d'جهت را نشان نمیدهد
compact تنها یک اندازه است، پس زمانی در آینده درست مانند زمانی در گذشته نمایش داده میشود (هر دو 5m). این سبک برای خوراک رویدادهای گذشته ساخته شده است. هرجا خواننده باید گذشته را از آینده بازشناسد، یکی از سبکهای دیگر را به کار ببر.
parseVttTimestamp / parseVttCueTiming
خواندن زمانبندی زیرنویس WebVTT: همان خطهای hh:mm:ss.mmm --> hh:mm:ss.mmm در یک فایل .vtt.
parseVttTimestamp یک مهر زمانی را (که hh: در آن اختیاری است) به ثانیه تبدیل میکند؛ parseVttCueTiming یک خط زمانبندی کامل را میخواند، یعنی هر دو سوی جداشده با --> را به { start, end } تبدیل میکند و تنظیمهای نشانهای که در انتها بیایند (align:start line:0) را نادیده میگیرد.
import { parseVttTimestamp, parseVttCueTiming } from 'ranuts/utils';
parseVttTimestamp('00:00:05.000'); // 5
parseVttTimestamp('01:05.250'); // 65.25
parseVttTimestamp('not a timestamp'); // undefined
parseVttCueTiming('00:00:00.000 --> 00:00:05.000'); // { start: 0, end: 5 }
parseVttCueTiming('00:00:05.000 --> 00:00:10.000 align:start line:0'); // { start: 5, end: 10 }هر دو وقتی ورودی جور درنیاید undefined برمیگردانند و هرگز خطا نمیاندازند، پس یک خط بدشکل در فایل زیرنویس را میتوان رد کرد بهجای آنکه کل خواندن از هم بپاشد.
یادداشتها
- گزینش یکا:
formatRelativeدرشتترین یکایی را برمیدارد که فاصله واقعاً آن را پر میکند و سپس درون همان گرد میکند. هرگاه گرد کردن روی آستانهٔ یکای بعدی بنشیند (۵۹٫۶ دقیقه که به «۶۰ دقیقه» گرد میشود)، یک پله بالا میرود تا «۱ ساعت پیش» خوانده شود. - گرد کردن متقارن: اندازه گرد میشود و سپس علامت دوباره بر آن نهاده میشود، چون در جاوااسکریپت
Math.round(-1.5)برابر-1است و در غیر این صورت ۹۰ دقیقه پیش «۱ ساعت پیش» خوانده میشد حال آنکه ۹۰ دقیقه بعد «۲ ساعت دیگر» میشد. - استفادهٔ دوباره از قالببند: نمونههای
Intl.RelativeTimeFormatبرای هر ترکیب زبان، سبک وnumericدر حافظهٔ نهان نگه داشته میشوند، پس فهرستی که صد مهر زمانی را میکشد یک قالببند میسازد، نه صد تا. - راه جایگزین: در محیط اجرایی که
Intl.RelativeTimeFormatندارد، خروجی بهجای خطا انداختن به شکل فشرده بازمیگردد.