Duration — فئة غير قابلة للتغيير من حزمة java.time تمثل المدة بين لحظتين زمنيتين بالثواني والنانوثانية. يقيس Duration الوقت المستند إلى الزمن — الساعات والدقائق والثواني والميلي ثانية والنانو ثانية. وفقاً لمواصفات Oracle Java 17 (2024)، على عكس Period (الذي يقيس السنوات-الأشهر-الأيام)، يعمل Duration بوحدات زمنية دقيقة ولا يعتمد على التقويم.
الخلاصة
Duration هي فئة تمثل مقدار الوقت بالثواني والنانو ثانية. إنها تمثل مدة زمنية مستندة إلى الوقت، أي عدد مادي من الثواني غير مرتبط بالتقويم. يمكن تصور Duration على أنها «le 125 دقيقة» أو «ساعتان و5 دقائق» — على عكس Period التي ستقول «شهرين».
يتكون التمثيل الداخلي لـ Duration من حقلين: long seconds (الثواني) و int nanos (النانو ثانية، من 0 إلى 999999999). يمكن أن تكون القيمة سالبة — وهذا يعني مدة “للخلف” في الزمن. القيمة القصوى هي ±31557014167219200 ثانية.
وفقاً لـ Baeldung (2024)، Duration هي فئة رئيسية لحساب مدة العمليات وتعيين المهلات وقياس الأداء. Duration غير قابلة للتغيير وآمنة للخيوط، مما يسمح باستخدامها في بيئات متعددة الخيوط دون مزامنة.
تنفذ الفئة الواجهات Comparable و TemporalAmount و TemporalUnit. تسمح TemporalAmount باستخدام Duration في طرق plus/minus للفئات LocalTime و LocalDateTime و Instant و ZonedDateTime.
الفرق الرئيسي هو أن Duration يقيس العدد الدقيق للثواني (مستند إلى الزمن)، بينما Period يقيس وحدات التقويم (مستند إلى التاريخ): سنوات، أشهر، أيام. Duration يقول: «مرت 86400 ثانية». Period يقول: «مر يوم واحد». يظهر الفرق أثناء تغييرات التوقيت الصيفي — يوم واحد في Period هو دائماً يوم تقويمي واحد، بينما 86400 ثانية في Duration قد تقابل 23 أو 25 ساعة أثناء DST.
يستخدم Duration لقياس الوقت الفيزيائي: مهلات الاتصال، وقت تنفيذ الاستعلام، الفترات بين Instant. يستخدم Period للحسابات التقويمية: عمر الشخص (Period.between(dateOfBirth, today))، مدة العقد.
يعمل Duration بالثواني والنانو ثانية، لذلك يمكن تقسيمه إلى أجزاء (ساعات، دقائق). يعمل Period بالسنوات والأشهر والأيام — وحدات تقويم غير قابلة للتجزئة. وفقاً لـ Oracle Java Tutorial (2024)، يعتمد الاختيار بين Duration و Period على نوع المهمة: وقت دقيق مقابل تواريخ تقويمية.
الطريقة الأكثر شيوعاً هي Duration.between(Temporal start, Temporal end). Temporal يمكن أن يكون Instant أو LocalTime أو LocalDateTime أو ZonedDateTime — أي نوع ينفذ Temporal. تعيد الطريقة Duration تمثل الفرق start - end (يمكن أن تكون سالبة).
طرق المصنع الثابتة: Duration.ofSeconds(long)، ofMinutes(long)، ofHours(long)، ofDays(long)، ofMillis(long)، ofNanos(long). يوجد أيضاً of(long amount, TemporalUnit unit) للوحدات التعسفية — ChronoUnit.HOURS و ChronoUnit.MINUTES وغيرها.
طريقة parse(CharSequence) تقبل نصاً بتنسيق ISO-8601: «PT1H30M» (ساعة و30 دقيقة)، «PT45S» (45 ثانية)، «P2DT3H» (يومان و3 ساعات). يبدأ النص دائماً بـ «PT» (Period of Time).
val betweenMoments = Duration.between(
Instant.parse("2026-07-21T10:00:00Z"),
Instant.parse("2026-07-21T14:30:00Z")
)
val fromMinutes = Duration.ofMinutes(90)
val fromHours = Duration.ofHours(2)
val parsed = Duration.parse("PT1H30M")
يدعم Duration مجموعة كاملة من العمليات الحسابية. الطريقتان plus(Duration) و minus(Duration) تضيفان أو تطرحان مدة أخرى. الطرق plusDays() و plusHours() و plusMinutes() و plusSeconds() و plusMillis() و plusNanos() — لإضافة وحدات محددة.
للضرب والقسمة، استخدم multipliedBy(long) و dividedBy(long). Duration.multipliedBy(2) تضاعف المدة. Duration.dividedBy(3) تقسم إلى ثلاثة أجزاء مع التقريب للأسفل. طريقة negated() تعكس الإشارة — الموجب يصبح سالباً والعكس صحيح.
طريقة abs() ترجع Duration بقيمة مطلقة (موجبة). isNegative() و isZero() للتحقق. toDays() و toHours() و toMinutes() و toSeconds() و toMillis() و toNanos() تحول إلى الوحدات المقابلة.
val oneHour = Duration.ofHours(1)
val twoHours = oneHour.plus(Duration.ofMinutes(60))
val halfHour = oneHour.dividedBy(2)
val minutes = twoHours.toMinutes()
val absDuration = (Duration.ofHours(-1)).abs()
تنفذ Duration واجهة Comparable، مما يسمح بمقارنة المدد بشكل طبيعي. ترجع طريقة compareTo() رقماً سالباً أو صفراً أو موجباً. isNegative() و isZero() للتحقق السريع. للمقارنة الصريحة، استخدم equals() — كائنا Duration متساويان إذا تطابقت ثوانيهما ونانو ثوانيهما.
نظراً لأن Duration يمكن أن تكون سالبة، فإن مقارنات “أكبر من” أو “أصغر من” تعمل مع مراعاة الإشارة. -5 دقائق أصغر من دقيقتين. طريقة abs() مفيدة لمقارنة الأطوال “المطلقة” بغض النظر عن الاتجاه.
في Kotlin، يدعم Duration عوامل المقارنة من خلال التحميل الزائد للمشغلين: a < b، a > b، a <= b. كما تتوفر plus و minus كمشغلين: a + b، a - b.
val short = Duration.ofMinutes(5)
val long = Duration.ofMinutes(10)
if (short < long) {
Log.d("Duration", "5 دقائق أقل من 10")
}
val negative = Duration.ofMinutes(-3)
Log.d("Duration", "سالب: ${negative.isNegative()}")
المثال الأول هو تكوين المزامنة الدورية مع الخادم. يستخدم Duration لحساب الفاصل بين المزامنات والتحقق مما إذا تم تجاوز الحد الزمني بدون تحديث.
data class SyncConfig(
val interval: Duration = Duration.ofMinutes(15),
val retryDelay: Duration = Duration.ofSeconds(30)
)
fun calculateNextSync(
lastSync: Instant,
config: SyncConfig
): Duration {
val elapsed = Duration.between(lastSync, Instant.now())
return config.interval.minus(elapsed)
.coerceAtLeast(Duration.ZERO)
}
المثال الثاني هو قياس وقت تنفيذ العملية لتسجيل الأداء.
fun measureExecution(
tag: String,
block: () -> Unit
) {
val start = Instant.now()
block()
val duration = Duration.between(start, Instant.now())
Log.d(tag, "تم التنفيذ في ${duration.toMillis()} ملي ثانية")
}
المثال الثالث هو حساب الوقت المتبقي للمؤقت (على سبيل المثال، العد التنازلي لنهاية العرض الترويجي).
class CountdownTimer(
private val expiresAt: Instant
) {
fun getRemainingTime(): Duration {
val remaining = Duration.between(
Instant.now(), expiresAt
)
return remaining.coerceAtLeast(Duration.ZERO)
}
fun isExpired(): Boolean = getRemainingTime() == Duration.ZERO
}
طريقة toString() ترجع Duration بتنسيق ISO-8601: «PT1H30M» (ساعة و30 دقيقة)، «PT45.5S» (45.5 ثانية). هذا التنسيق مناسب للتبادل بين الآلات، لكنه ليس للعرض على المستخدم.
لتنسيق قابل للقراءة البشرية، استخدم toDays() و toHours() و toMinutes() و toSeconds() يليه بناء النص يدوياً. على سبيل المثال: «${days} ي ${hours} س ${minutes} د». لاحظ أن toHours() ترجع العدد الإجمالي للساعات، وليس الساعات ضمن اليوم.
لتقسيم Duration إلى مكونات، استخدم الصيغة: val hours = duration.toHours(); val minutes = duration.toMinutes() % 60; val seconds = duration.seconds % 60. وفقاً لـ Apache Commons Lang (2024)، توفر مكتبة DurationFormatUtils إمكانيات تنسيق إضافية.
fun formatDuration(duration: Duration): String {
val hours = duration.toHours()
val minutes = duration.toMinutes() % 60
val seconds = duration.seconds % 60
return buildString {
if (hours > 0) append("${hours} h ")
if (minutes > 0) append("${minutes} min ")
append("${seconds} sec")
}
}
الخطأ الأول هو الخلط بين Duration و Period عند العمل مع التواريخ. Duration يقيس الثواني، لذلك Duration.ofDays(1) هي دائماً 24 ساعة (86400 ثانية)، بغض النظر عن تغييرات التوقيت الصيفي. إذا كنت بحاجة إلى يوم تقويمي، استخدم Period.ofDays(1).
الخطأ الثاني هو فقدان النانو ثانية أثناء التحويل. يمكن لـ Duration تخزين النانو ثانية، لكن toMillis() و toSeconds() تتجاهلهما. للحسابات الدقيقة، استخدم toNanos() أو اعمل مع Duration مباشرة دون تحويل إلى أنواع بدائية.
الخطأ الثالث هو تجاهل Duration السالبة. Duration.between(start, end) ترجع start - end. إذا كان start بعد end، ستكون Duration سالبة. تساعد طريقة abs() في الحصول على القيمة المطلقة، و isNegative() تتحقق من ترتيب الوسائط.
الخطأ الرابع هو تنسيق Duration بشكل غير صحيح لواجهة المستخدم. Duration.toString() ترجع ISO-8601، وهو غير قابل للقراءة. قم دائماً بتنسيق Duration يدوياً للعرض على المستخدم باستخدام toHours() و toMinutes() و toSeconds() مع الباقي الصحيح من القسمة.
الأسئلة الشائعة
نعم، Duration يمكن أن تكون سالبة. Duration.between(start, end) ترجع start - end. إذا كان start بعد end، ستكون Duration سالبة. استخدم abs() للحصول على القيمة المطلقة أو isNegative() للتحقق.
استخدم طريقة plus(Duration) أو العامل + في Kotlin: duration1 + duration2. النتيجة هي Duration جديدة. طريقة minus(Duration) تطرح مدة من أخرى. جميع العمليات غير قابلة للتغيير وتعيد كائناً جديداً.
Duration.ofDays(1) هي دائماً 24 ساعة (86400 ثانية). Period.ofDays(1) هو يوم تقويمي واحد، والذي قد يكون 23 أو 25 ساعة أثناء DST. للحسابات الزمنية الدقيقة، استخدم Duration؛ للحسابات التقويمية، استخدم Period.
استخدم طريقة toMillis(). ترجع long — عدد الميلي ثانية في Duration. للنانو ثانية، استخدم toNanos(). تنبيه: toNanos() قد يفيض في القيم > 292 سنة. لـ Duration الكبيرة، استخدم toSeconds() أو toMinutes().
استخدم Duration.between(startTime, endTime). إذا كان endTime أقل من startTime (المناوبة الليلية)، ستكون Duration سالبة. أضف 24 ساعة: duration.plusHours(24)، إذا كان من المفترض أن endTime هو اليوم التالي.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.