1 package eu.fbk.dkm.pikes.rdf.util;
2
3 import com.google.common.base.Preconditions;
4 import com.google.common.base.Strings;
5 import eu.fbk.dkm.pikes.rdf.vocab.OWLTIME;
6 import eu.fbk.rdfpro.util.Statements;
7 import org.eclipse.rdf4j.model.Resource;
8 import org.eclipse.rdf4j.model.IRI;
9 import org.eclipse.rdf4j.model.Value;
10 import org.eclipse.rdf4j.model.vocabulary.RDF;
11 import org.eclipse.rdf4j.model.vocabulary.RDFS;
12 import org.eclipse.rdf4j.rio.RDFHandler;
13 import org.eclipse.rdf4j.rio.RDFHandlerException;
14
15 import javax.annotation.Nullable;
16 import java.util.Calendar;
17 import java.util.GregorianCalendar;
18 import java.util.Objects;
19 import java.util.regex.Pattern;
20
21 public class OWLTime {
22
23 private static int parseOptInt(final String string) {
24 if (string.contains("X")) {
25 return -1;
26 }
27 return Integer.parseInt(string);
28 }
29
30 private static String formatOptInt(final int value, final boolean fourDigits) {
31 return fourDigits ? value == -1 ? "XXXX" : String.format("%04d", value)
32 : value == -1 ? "XX" : String.format("%02d", value);
33 }
34
35 private static void emit(final RDFHandler handler, final Resource subj, final IRI pred,
36 final Object obj, final Resource ctx) throws RDFHandlerException {
37 final Value o = Statements.convert(obj, Value.class);
38 if (subj != null && pred != null && o != null) {
39 if (ctx == null) {
40 handler.handleStatement(Statements.VALUE_FACTORY.createStatement(subj, pred, o));
41 } else {
42 handler.handleStatement(Statements.VALUE_FACTORY.createStatement(subj, pred, o,
43 ctx));
44 }
45 }
46 }
47
48 public static final class Interval {
49
50 private static final Pattern DATE_TIME_PATTERN = Pattern
51 .compile("(?:PRESENT_REF|PAST_REF|FUTURE_REF|[0-9X]{4}"
52 + "(?:-(?:[0-9X]{2}|W[0-9X]{2}|SP|SU|FA|WI)(?:-(?:[0-9X]{2}|WE))?)?)?"
53 + "T?(?:MO|MI|AF|EV|NI|PM|DT|[0-9X]{2}(?:\\:[0-9X]{2}(?:\\:[0-9X]{2})?)?)?");
54
55 private static final Interval UNKNOWN = new Interval(null, null);
56
57 @Nullable
58 private final DateTime begin;
59
60 @Nullable
61 private final DateTime end;
62
63 private Interval(@Nullable final DateTime begin, @Nullable final DateTime end) {
64 this.begin = begin;
65 this.end = end;
66 }
67
68 public static Interval create(@Nullable final DateTime dateTime) {
69 return dateTime == null ? UNKNOWN : new Interval(dateTime, dateTime);
70 }
71
72 public static Interval create(@Nullable final DateTime begin, @Nullable final DateTime end) {
73 return begin == null && end == null ? UNKNOWN : new Interval(begin, end);
74
75 }
76
77 public static Interval create(@Nullable final Interval begin, @Nullable final Interval end) {
78 return create(begin == null ? null : begin.getBegin(),
79 end == null ? null : end.getEnd());
80 }
81
82 public static Interval parseTimex(final String value) {
83
84
85 int century = -1;
86 int decade = -1;
87 int year = -1;
88 String season = null;
89 int month = -1;
90 int week = -1;
91 boolean weekend = false;
92 int day = -1;
93 int hour = -1;
94 int minute = -1;
95 int second = -1;
96
97
98 final String normValue = value.trim().toUpperCase();
99 if (normValue.isEmpty() || !DATE_TIME_PATTERN.matcher(normValue).matches()) {
100 return null;
101 }
102 final int timeIndex = normValue.endsWith("_REF") ? -1 : normValue.indexOf('T');
103 final String timePart = timeIndex >= 0 ? normValue.substring(timeIndex + 1) : null;
104 final String datePart = timeIndex >= 0 ? normValue.substring(0, timeIndex) : normValue
105 .contains(":") ? null : normValue;
106
107
108 if (!Strings.isNullOrEmpty(datePart)) {
109 if (datePart.equals("PRESENT_REF") || datePart.equals("PAST_REF")
110 || datePart.equals("FUTURE_REF")) {
111
112 } else {
113 final String[] tokens = datePart.split("-");
114 if (Character.isDigit(tokens[0].charAt(0))
115 && !Character.isDigit(tokens[0].charAt(tokens[0].length() - 1))) {
116 if (tokens[0].length() == 4 && Character.isDigit(tokens[0].charAt(1))) {
117 if (Character.isDigit(tokens[0].charAt(2))) {
118 decade = Integer.parseInt(tokens[0].substring(0, 3)) * 10;
119 } else {
120 century = Integer.parseInt(tokens[0].substring(0, 2)) * 100;
121 }
122 } else {
123 return null;
124 }
125 } else {
126 year = parseOptInt(tokens[0]);
127 if (tokens.length >= 2) {
128 if (!Character.isDigit(tokens[1].charAt(tokens[1].length() - 1))) {
129 season = tokens[1];
130 } else if (tokens[1].charAt(0) == 'W') {
131 week = parseOptInt(tokens[1].substring(1));
132 if (tokens.length >= 3 && tokens[2].equals("WE")) {
133 weekend = true;
134 }
135 } else {
136 month = parseOptInt(tokens[1]);
137 day = tokens.length >= 3 ? parseOptInt(tokens[2]) : -1;
138 }
139 }
140 }
141 }
142 }
143
144
145 if (timePart != null) {
146 if (timePart.equals("MO") || timePart.equals("MI") || timePart.equals("AF")
147 || timePart.equals("EV") || timePart.equals("NI") || timePart.equals("PM")
148 || timePart.equals("DT")) {
149
150 } else {
151 final String[] tokens = timePart.split(":");
152 hour = parseOptInt(tokens[0]);
153 if (tokens.length >= 2) {
154 minute = parseOptInt(tokens[1]);
155 if (tokens.length >= 3) {
156 second = parseOptInt(tokens[2]);
157 }
158 }
159 }
160 }
161
162
163 final String fieldMsg = "Unexpected date/time field(s)";
164 if (century != -1) {
165 Preconditions.checkArgument(decade == -1 && year == -1 && season == null
166 && month == -1 && week == -1 && !weekend && day == -1 && hour == -1
167 && minute == -1 && second == -1, fieldMsg);
168 final DateTime begin = DateTime.create(century, 1, -1, 1, -1, -1, -1);
169 final DateTime end = DateTime.create(century + 99, 12, -1, 31, -1, -1, -1);
170 return create(begin, end);
171
172 } else if (decade != -1) {
173 Preconditions.checkArgument(year == -1 && season == null && month == -1
174 && week == -1 && !weekend && day == -1 && hour == -1 && minute == -1
175 && second == -1, fieldMsg);
176 final DateTime begin = DateTime.create(decade, 1, -1, 1, -1, -1, -1);
177 final DateTime end = DateTime.create(decade + 9, 12, -1, 31, -1, -1, -1);
178 return create(begin, end);
179
180 } else if (season != null) {
181 Preconditions.checkArgument(month == -1 && week == -1 && !weekend && day == -1
182 && hour == -1 && minute == -1 && second == -1, fieldMsg);
183
184
185 DateTime begin;
186 DateTime end;
187 if (season.equals("SP")) {
188 begin = DateTime.create(year - 1, 12, -1, 21, -1, -1, -1);
189 end = DateTime.create(year, 3, -1, 19, -1, -1, -1);
190 } else if (season.equals("SU")) {
191 begin = DateTime.create(year, 3, -1, 20, -1, -1, -1);
192 end = DateTime.create(year, 6, -1, 20, -1, -1, -1);
193 } else if (season.equals("FA")) {
194 begin = DateTime.create(year, 6, -1, 21, -1, -1, -1);
195 end = DateTime.create(year, 9, -1, 21, -1, -1, -1);
196 } else if (season.equals("WI")) {
197 begin = DateTime.create(year, 9, -1, 22, -1, -1, -1);
198 end = DateTime.create(year, 12, -1, 29, -1, -1, -1);
199 } else {
200 throw new IllegalArgumentException("Unexpected season ID: " + season);
201 }
202 return create(begin, end);
203
204 } else if (weekend) {
205 Preconditions.checkArgument(year != -1 && week != -1 && month == -1 && day == -1
206 && hour == -1 && minute == -1 && second == -1, fieldMsg);
207 final GregorianCalendar c = new GregorianCalendar();
208 c.setFirstDayOfWeek(Calendar.MONDAY);
209 c.setMinimalDaysInFirstWeek(1);
210 c.set(Calendar.YEAR, year);
211 c.set(Calendar.WEEK_OF_YEAR, week);
212 c.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
213 final DateTime begin = DateTime.create(c.get(Calendar.YEAR),
214 c.get(Calendar.MONTH) + 1, c.get(Calendar.WEEK_OF_YEAR),
215 c.get(Calendar.DAY_OF_MONTH), -1, -1, -1);
216 c.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
217 final DateTime end = DateTime.create(c.get(Calendar.YEAR),
218 c.get(Calendar.MONTH) + 1, c.get(Calendar.WEEK_OF_YEAR),
219 c.get(Calendar.DAY_OF_MONTH), -1, -1, -1);
220 return create(begin, end);
221
222 } else {
223 return create(DateTime.create(year, month, week, day, hour, minute, second));
224 }
225 }
226
227 public boolean isDateTimeInterval() {
228 return this.begin != null && this.end != null && this.begin.equals(this.end);
229 }
230
231 @Nullable
232 public DateTime getBegin() {
233 return this.begin;
234 }
235
236 @Nullable
237 public DateTime getEnd() {
238 return this.end;
239 }
240
241 @Override
242 public boolean equals(final Object object) {
243 if (object == this) {
244 return true;
245 }
246 if (!(object instanceof Interval)) {
247 return false;
248 }
249 final Interval other = (Interval) object;
250 return Objects.equals(this.begin, other.begin) && Objects.equals(this.end, other.end);
251 }
252
253 @Override
254 public int hashCode() {
255 return Objects.hash(this.begin, this.end);
256 }
257
258 public IRI toRDF(final RDFHandler handler, final String namespace, final Resource ctx)
259 throws RDFHandlerException {
260 final IRI iri = toIRI(namespace);
261 if (isDateTimeInterval()) {
262 final IRI iriDesc = this.begin.toRDF(handler, namespace, ctx);
263 emit(handler, iri, OWLTIME.HAS_DATE_TIME_DESCRIPTION, iriDesc, ctx);
264 emit(handler, iri, RDF.TYPE, OWLTIME.DATE_TIME_INTERVAL, ctx);
265 } else {
266 final IRI beginIRI = this.begin == null ? null : create(this.begin).toRDF(handler,
267 namespace, ctx);
268 final IRI endIRI = this.end == null ? null : create(this.end).toRDF(handler,
269 namespace, ctx);
270 emit(handler, iri, OWLTIME.INTERVAL_STARTED_BY, beginIRI, ctx);
271 emit(handler, iri, OWLTIME.INTERVAL_FINISHED_BY, endIRI, ctx);
272 }
273 emit(handler, iri, RDF.TYPE, OWLTIME.PROPER_INTERVAL, ctx);
274 emit(handler, iri, RDFS.LABEL, toString(), ctx);
275 return iri;
276 }
277
278 public IRI toIRI(final String namespace) {
279 final String localName = toString().replace(" - ", "_").replace(':', '.');
280 return Statements.VALUE_FACTORY.createIRI(namespace, localName);
281 }
282
283 @Override
284 public String toString() {
285 if (isDateTimeInterval()) {
286 return this.begin.toString();
287 } else {
288 return (this.begin == null ? "null" : this.begin.toString()) + " - "
289 + (this.end == null ? "null" : this.end.toString());
290 }
291 }
292
293 }
294
295 public static final class DateTime {
296
297 private final int year;
298
299 private final int month;
300
301 private final int week;
302
303 private final int day;
304
305 private final int dayOfWeek;
306
307 private final int hour;
308
309 private final int minute;
310
311 private final int second;
312
313 private DateTime(final int year, final int month, final int week, final int day,
314 final int dayOfWeek, final int hour, final int minute, final int second) {
315 this.year = year;
316 this.month = month;
317 this.week = week;
318 this.day = day;
319 this.dayOfWeek = dayOfWeek;
320 this.hour = hour;
321 this.minute = minute;
322 this.second = second;
323 }
324
325 public static DateTime create(final int year, int month, int week, final int day,
326 final int hour, final int minute, final int second) {
327
328
329 int dayOfWeek = -1;
330 if (year != -1 && (week != -1 || month != -1 && day != -1)) {
331 final GregorianCalendar c = new GregorianCalendar();
332 c.setFirstDayOfWeek(Calendar.MONDAY);
333 c.setMinimalDaysInFirstWeek(1);
334 c.set(Calendar.YEAR, year);
335 if (month != -1 && day != -1) {
336 c.set(Calendar.MONTH, month - 1);
337 c.set(Calendar.DAY_OF_MONTH, day);
338 dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
339 if (week == -1) {
340 week = c.get(Calendar.WEEK_OF_YEAR);
341 }
342 } else {
343 if (day != -1) {
344 c.set(Calendar.DAY_OF_MONTH, day);
345 for (int i = 0; i < 12; ++i) {
346 c.set(Calendar.MONTH, i);
347 if (c.get(Calendar.WEEK_OF_YEAR) == week) {
348 month = i + 1;
349 dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
350 break;
351 }
352 }
353 } else if (week == 1) {
354 month = 1;
355 } else {
356 c.set(Calendar.WEEK_OF_YEAR, week);
357 c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
358 month = c.get(Calendar.MONTH) + 1;
359 }
360 }
361 }
362
363 return new DateTime(year, month, week, day, dayOfWeek, hour, minute, second);
364 }
365
366 public int getYear() {
367 return this.year;
368 }
369
370 public int getMonth() {
371 return this.month;
372 }
373
374 public int getWeek() {
375 return this.week;
376 }
377
378 public int getDay() {
379 return this.day;
380 }
381
382 public int getDayOfWeek() {
383 return this.dayOfWeek;
384 }
385
386 public int getHour() {
387 return this.hour;
388 }
389
390 public int getMinute() {
391 return this.minute;
392 }
393
394 public int getSecond() {
395 return this.second;
396 }
397
398 @Override
399 public boolean equals(final Object object) {
400 if (object == this) {
401 return true;
402 }
403 if (!(object instanceof DateTime)) {
404 return false;
405 }
406 final DateTime other = (DateTime) object;
407 return this.year == other.year && this.month == other.month && this.week == other.week
408 && this.day == other.day && this.hour == other.hour
409 && this.minute == other.minute && this.second == other.second;
410 }
411
412 @Override
413 public int hashCode() {
414 return Objects.hash(this.year, this.month, this.week, this.day, this.hour,
415 this.minute, this.second);
416 }
417
418 public IRI toRDF(final RDFHandler handler, final String namespace,
419 @Nullable final Resource ctx) throws RDFHandlerException {
420
421
422
423
424 final IRI iri = toIRI(namespace);
425 IRI unitType = null;
426 emit(handler, iri, RDF.TYPE, OWLTIME.DATE_TIME_DESCRIPTION, ctx);
427 if (this.year != -1) {
428 emit(handler, iri, OWLTIME.YEAR, this.year, ctx);
429 unitType = OWLTIME.UNIT_YEAR;
430 }
431 if (this.month != -1) {
432 emit(handler, iri, OWLTIME.MONTH, this.month, ctx);
433 unitType = OWLTIME.UNIT_MONTH;
434 }
435 if (this.week != -1) {
436 emit(handler, iri, OWLTIME.WEEK, this.week, ctx);
437 unitType = OWLTIME.UNIT_WEEK;
438 }
439 if (this.day != -1) {
440 emit(handler, iri, OWLTIME.DAY, this.day, ctx);
441 unitType = OWLTIME.UNIT_DAY;
442 }
443 if (this.dayOfWeek != -1) {
444 IRI dayIRI;
445 if (this.dayOfWeek == Calendar.MONDAY) {
446 dayIRI = OWLTIME.MONDAY;
447 } else if (this.dayOfWeek == Calendar.TUESDAY) {
448 dayIRI = OWLTIME.TUESDAY;
449 } else if (this.dayOfWeek == Calendar.WEDNESDAY) {
450 dayIRI = OWLTIME.WEDNESDAY;
451 } else if (this.dayOfWeek == Calendar.THURSDAY) {
452 dayIRI = OWLTIME.THURSDAY;
453 } else if (this.dayOfWeek == Calendar.FRIDAY) {
454 dayIRI = OWLTIME.FRIDAY;
455 } else if (this.dayOfWeek == Calendar.SATURDAY) {
456 dayIRI = OWLTIME.SATURDAY;
457 } else {
458 dayIRI = OWLTIME.SUNDAY;
459 }
460 emit(handler, iri, OWLTIME.DAY_OF_WEEK, dayIRI, ctx);
461 }
462 if (this.hour != -1) {
463 emit(handler, iri, OWLTIME.HOUR, this.hour, ctx);
464 unitType = OWLTIME.UNIT_HOUR;
465 }
466 if (this.minute != -1) {
467 emit(handler, iri, OWLTIME.MINUTE, this.minute, ctx);
468 unitType = OWLTIME.UNIT_MINUTE;
469 }
470 if (this.second != -1) {
471 emit(handler, iri, OWLTIME.SECOND, this.second, ctx);
472 unitType = OWLTIME.UNIT_SECOND;
473 }
474 emit(handler, iri, OWLTIME.UNIT_TYPE, unitType, ctx);
475 return iri;
476 }
477
478 public IRI toIRI(final String namespace) {
479 return Statements.VALUE_FACTORY.createIRI(namespace, toString().replace(':', '.')
480 + "_desc");
481 }
482
483 @Override
484 public String toString() {
485
486 final StringBuilder builder = new StringBuilder();
487 final boolean hasDate = this.year != -1 || this.month != -1 || this.week != -1
488 || this.day != -1;
489 final boolean hasTime = this.hour != -1 || this.minute != -1 || this.second != -1;
490 if (hasDate) {
491 builder.append(formatOptInt(this.year, true));
492 if (this.week != -1 && this.day == -1) {
493 builder.append("-W").append(formatOptInt(this.week, false));
494 } else if (hasTime || this.month != -1 || this.day != -1) {
495 builder.append('-').append(formatOptInt(this.month, false));
496 if (hasTime || this.day != -1) {
497 builder.append('-').append(formatOptInt(this.day, false));
498 }
499 }
500 }
501 if (hasTime) {
502 if (hasDate) {
503 builder.append('T');
504 }
505 builder.append(formatOptInt(this.hour, false));
506 if (this.minute != -1 || this.second != -1) {
507 builder.append(':').append(formatOptInt(this.minute, false));
508 if (this.second != -1) {
509 builder.append(':').append(formatOptInt(this.second, false));
510 }
511 }
512 }
513 return builder.toString();
514 }
515
516 }
517
518 public static final class Duration {
519
520 private static final Pattern DURATION_PATTERN = Pattern
521 .compile("P(?:[0-9X]+Y)?(?:[0-9X]+M)?(?:[0-9X]+W)?(?:[0-9X]+D)?"
522 + "(?:T(?:[0-9X]+H)?(?:[0-9X]+M)?(?:[0-9X]+S)?)?");
523
524 private final int years;
525
526 private final int months;
527
528 private final int weeks;
529
530 private final int days;
531
532 private final int hours;
533
534 private final int minutes;
535
536 private final int seconds;
537
538 private Duration(final int years, final int months, final int weeks, final int days,
539 final int hours, final int minutes, final int seconds) {
540 this.years = years;
541 this.months = months;
542 this.weeks = weeks;
543 this.days = days;
544 this.hours = hours;
545 this.minutes = minutes;
546 this.seconds = seconds;
547 }
548
549 public static Duration create(final int years, final int months, final int weeks,
550 final int days, final int hours, final int minutes, final int seconds) {
551 Preconditions.checkArgument(years >= 0);
552 Preconditions.checkArgument(months >= 0);
553 Preconditions.checkArgument(weeks >= 0);
554 Preconditions.checkArgument(days >= 0);
555 Preconditions.checkArgument(hours >= 0);
556 Preconditions.checkArgument(minutes >= 0);
557 Preconditions.checkArgument(seconds >= 0);
558 return new Duration(years, months, weeks, days, hours, minutes, seconds);
559 }
560
561 @Nullable
562 public static Duration parseTimex(final String value) {
563
564 final String normalizedValue = value.trim().toUpperCase();
565 if (!DURATION_PATTERN.matcher(value).matches()) {
566 return null;
567 }
568
569 int years = 0;
570 int months = 0;
571 int weeks = 0;
572 int days = 0;
573 int hours = 0;
574 int minutes = 0;
575 int seconds = 0;
576 boolean unknown = true;
577
578 try {
579 Preconditions.checkArgument(normalizedValue.startsWith("P"));
580 int start = 1;
581 boolean insideTime = false;
582 for (int i = 1; i < normalizedValue.length(); ++i) {
583 final char ch = normalizedValue.charAt(i);
584 if (ch == 'T') {
585 insideTime = true;
586 start = i + 1;
587 } else if (!Character.isDigit(ch) && ch != 'X') {
588 final int v = parseOptInt(normalizedValue.substring(start, i));
589 unknown &= v == -1;
590 if (v > 0) {
591 if (ch == 'Y') {
592 years = v;
593 } else if (ch == 'M' && !insideTime) {
594 months = v;
595 } else if (ch == 'W') {
596 weeks = v;
597 } else if (ch == 'D') {
598 days = v;
599 } else if (ch == 'H') {
600 hours = v;
601 } else if (ch == 'M' && insideTime) {
602 minutes = v;
603 } else if (ch == 'S') {
604 seconds = v;
605 } else {
606 throw new IllegalArgumentException("Invalid flag " + ch + " in "
607 + value);
608 }
609 }
610 start = i + 1;
611 }
612 }
613 } catch (final Throwable ex) {
614 throw new IllegalArgumentException("Invalid duration string: '" + value + "'", ex);
615 }
616
617
618
619
620 if (unknown) {
621 return null;
622 }
623
624 return create(years, months, weeks, days, hours, minutes, seconds);
625 }
626
627 public int getYears() {
628 return this.years;
629 }
630
631 public int getMinutes() {
632 return this.minutes;
633 }
634
635 public int getWeeks() {
636 return this.weeks;
637 }
638
639 public int getDays() {
640 return this.days;
641 }
642
643 public int getHours() {
644 return this.hours;
645 }
646
647 public int getMonths() {
648 return this.months;
649 }
650
651 public int getSeconds() {
652 return this.seconds;
653 }
654
655 @Override
656 public boolean equals(final Object object) {
657 if (object == this) {
658 return true;
659 }
660 if (!(object instanceof Duration)) {
661 return false;
662 }
663 final Duration other = (Duration) object;
664 return this.years == other.years && this.months == other.months
665 && this.weeks == other.weeks && this.days == other.days
666 && this.hours == other.hours && this.minutes == other.minutes
667 && this.seconds == other.seconds;
668 }
669
670 @Override
671 public int hashCode() {
672 return Objects.hash(this.years, this.months, this.weeks, this.days, this.hours,
673 this.minutes, this.seconds);
674 }
675
676 public IRI toRDF(final RDFHandler handler, final String namespace,
677 @Nullable final Resource ctx) throws RDFHandlerException {
678 final IRI iri = toIRI(namespace);
679 emit(handler, iri, RDF.TYPE, OWLTIME.DURATION_DESCRIPTION, ctx);
680 if (this.years > 0) {
681 emit(handler, iri, OWLTIME.YEARS, this.years, ctx);
682 }
683 if (this.months > 0) {
684 emit(handler, iri, OWLTIME.MONTHS, this.months, ctx);
685 }
686 if (this.weeks > 0) {
687 emit(handler, iri, OWLTIME.WEEKS, this.weeks, ctx);
688 }
689 if (this.days > 0) {
690 emit(handler, iri, OWLTIME.YEARS, this.days, ctx);
691 }
692 if (this.hours > 0) {
693 emit(handler, iri, OWLTIME.HOURS, this.hours, ctx);
694 }
695 if (this.minutes > 0) {
696 emit(handler, iri, OWLTIME.MINUTES, this.minutes, ctx);
697 }
698 if (this.seconds > 0) {
699 emit(handler, iri, OWLTIME.SECONDS, this.seconds, ctx);
700 }
701 emit(handler, iri, RDFS.LABEL, toString(), ctx);
702 return iri;
703 }
704
705 public IRI toIRI(final String namespace) {
706 return Statements.VALUE_FACTORY.createIRI(namespace, toString() + "_desc");
707 }
708
709 @Override
710 public String toString() {
711 final StringBuilder builder = new StringBuilder("P");
712 if (this.years > 0) {
713 builder.append(this.years).append('Y');
714 }
715 if (this.months > 0) {
716 builder.append(this.months).append('M');
717 }
718 if (this.weeks > 0) {
719 builder.append(this.weeks).append('W');
720 }
721 if (this.days > 0) {
722 builder.append(this.days).append('D');
723 }
724 if (this.hours > 0 || this.minutes > 0 || this.seconds > 0) {
725 builder.append('T');
726 }
727 if (this.hours > 0) {
728 builder.append(this.hours).append('H');
729 }
730 if (this.minutes > 0) {
731 builder.append(this.minutes).append('M');
732 }
733 if (this.seconds > 0) {
734 builder.append(this.seconds).append('S');
735 }
736 return builder.toString();
737 }
738
739 }
740
741 }