or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

error-handling.mdframework-configuration.mdhttp-caching.mdindex.mdjsr310-parameters.mdoptional-handling.mdparameter-handling.mdsession-management.mdvalidation.md

jsr310-parameters.mddocs/

0

# JSR310 Date/Time Parameters

1

2

Parameter converters for Java 8 date/time API types providing type-safe parsing of date and time values from HTTP requests. Supports all major JSR310 temporal types with automatic validation and error handling.

3

4

## Capabilities

5

6

### Instant Parameters

7

8

Parameter converters for Instant values representing points in time.

9

10

```java { .api }

11

/**

12

* Parameter wrapper for Instant values

13

* Parses ISO-8601 instant strings (e.g., "2023-12-25T10:30:00Z")

14

*/

15

public class InstantParam extends AbstractParam<Instant> {

16

17

/** Creates InstantParam from ISO-8601 string input */

18

public InstantParam(String input);

19

20

/** Creates InstantParam with custom parameter name for error messages */

21

public InstantParam(String input, String parameterName);

22

}

23

24

/**

25

* Parameter wrapper for Instant values from seconds since epoch

26

* Parses numeric strings as seconds since Unix epoch

27

*/

28

public class InstantSecondParam extends AbstractParam<Instant> {

29

30

/** Creates InstantSecondParam from seconds string input */

31

public InstantSecondParam(String input);

32

33

/** Creates InstantSecondParam with custom parameter name */

34

public InstantSecondParam(String input, String parameterName);

35

}

36

```

37

38

**Usage Examples:**

39

40

```java

41

import io.dropwizard.jersey.jsr310.*;

42

import jakarta.ws.rs.*;

43

import java.time.Instant;

44

45

@Path("/events")

46

public class EventResource {

47

48

@GET

49

public List<Event> getEvents(@QueryParam("since") InstantParam since,

50

@QueryParam("until") InstantParam until) {

51

Instant sinceTime = since != null ? since.get() : Instant.now().minus(Duration.ofDays(7));

52

Instant untilTime = until != null ? until.get() : Instant.now();

53

54

return eventService.getEventsBetween(sinceTime, untilTime);

55

}

56

57

@GET

58

@Path("/unix")

59

public List<Event> getEventsUnix(@QueryParam("since") InstantSecondParam since) {

60

// Handles Unix timestamps like "1703505000"

61

Instant sinceTime = since != null ? since.get() : Instant.now().minus(Duration.ofDays(1));

62

return eventService.getEventsSince(sinceTime);

63

}

64

}

65

66

// Example URLs:

67

// GET /events?since=2023-12-25T10:30:00Z&until=2023-12-26T10:30:00Z

68

// GET /events/unix?since=1703505000

69

```

70

71

### Local Date/Time Parameters

72

73

Parameter converters for local date and time values without timezone information.

74

75

```java { .api }

76

/**

77

* Parameter wrapper for LocalDate values

78

* Parses ISO-8601 date strings (e.g., "2023-12-25")

79

*/

80

public class LocalDateParam extends AbstractParam<LocalDate> {

81

82

/** Creates LocalDateParam from ISO-8601 date string */

83

public LocalDateParam(String input);

84

85

/** Creates LocalDateParam with custom parameter name */

86

public LocalDateParam(String input, String parameterName);

87

}

88

89

/**

90

* Parameter wrapper for LocalDateTime values

91

* Parses ISO-8601 date-time strings (e.g., "2023-12-25T10:30:00")

92

*/

93

public class LocalDateTimeParam extends AbstractParam<LocalDateTime> {

94

95

/** Creates LocalDateTimeParam from ISO-8601 date-time string */

96

public LocalDateTimeParam(String input);

97

98

/** Creates LocalDateTimeParam with custom parameter name */

99

public LocalDateTimeParam(String input, String parameterName);

100

}

101

102

/**

103

* Parameter wrapper for LocalTime values

104

* Parses ISO-8601 time strings (e.g., "10:30:00")

105

*/

106

public class LocalTimeParam extends AbstractParam<LocalTime> {

107

108

/** Creates LocalTimeParam from ISO-8601 time string */

109

public LocalTimeParam(String input);

110

111

/** Creates LocalTimeParam with custom parameter name */

112

public LocalTimeParam(String input, String parameterName);

113

}

114

```

115

116

**Usage Examples:**

117

118

```java

119

import java.time.*;

120

import jakarta.ws.rs.*;

121

122

@Path("/schedule")

123

public class ScheduleResource {

124

125

@GET

126

@Path("/daily")

127

public List<Appointment> getDailySchedule(@QueryParam("date") LocalDateParam date) {

128

LocalDate scheduleDate = date != null ? date.get() : LocalDate.now();

129

return scheduleService.getAppointmentsForDate(scheduleDate);

130

}

131

132

@GET

133

@Path("/appointments")

134

public List<Appointment> getAppointments(@QueryParam("from") LocalDateTimeParam from,

135

@QueryParam("to") LocalDateTimeParam to) {

136

LocalDateTime fromTime = from != null ? from.get() : LocalDateTime.now();

137

LocalDateTime toTime = to != null ? to.get() : fromTime.plusDays(1);

138

139

return scheduleService.getAppointmentsBetween(fromTime, toTime);

140

}

141

142

@GET

143

@Path("/available")

144

public List<TimeSlot> getAvailableSlots(@QueryParam("date") LocalDateParam date,

145

@QueryParam("after") LocalTimeParam afterTime) {

146

LocalDate checkDate = date != null ? date.get() : LocalDate.now();

147

LocalTime startTime = afterTime != null ? afterTime.get() : LocalTime.of(9, 0);

148

149

return scheduleService.getAvailableSlots(checkDate, startTime);

150

}

151

}

152

153

// Example URLs:

154

// GET /schedule/daily?date=2023-12-25

155

// GET /schedule/appointments?from=2023-12-25T09:00:00&to=2023-12-25T17:00:00

156

// GET /schedule/available?date=2023-12-25&after=10:30:00

157

```

158

159

### Offset and Zoned Date/Time Parameters

160

161

Parameter converters for date/time values with timezone information.

162

163

```java { .api }

164

/**

165

* Parameter wrapper for OffsetDateTime values

166

* Parses ISO-8601 offset date-time strings (e.g., "2023-12-25T10:30:00+01:00")

167

*/

168

public class OffsetDateTimeParam extends AbstractParam<OffsetDateTime> {

169

170

/** Creates OffsetDateTimeParam from ISO-8601 offset date-time string */

171

public OffsetDateTimeParam(String input);

172

173

/** Creates OffsetDateTimeParam with custom parameter name */

174

public OffsetDateTimeParam(String input, String parameterName);

175

}

176

177

/**

178

* Parameter wrapper for ZonedDateTime values

179

* Parses ISO-8601 zoned date-time strings (e.g., "2023-12-25T10:30:00[Europe/London]")

180

*/

181

public class ZonedDateTimeParam extends AbstractParam<ZonedDateTime> {

182

183

/** Creates ZonedDateTimeParam from ISO-8601 zoned date-time string */

184

public ZonedDateTimeParam(String input);

185

186

/** Creates ZonedDateTimeParam with custom parameter name */

187

public ZonedDateTimeParam(String input, String parameterName);

188

}

189

190

/**

191

* Parameter wrapper for ZoneId values

192

* Parses zone ID strings (e.g., "Europe/London", "UTC", "+01:00")

193

*/

194

public class ZoneIdParam extends AbstractParam<ZoneId> {

195

196

/** Creates ZoneIdParam from zone ID string */

197

public ZoneIdParam(String input);

198

199

/** Creates ZoneIdParam with custom parameter name */

200

public ZoneIdParam(String input, String parameterName);

201

}

202

```

203

204

**Usage Examples:**

205

206

```java

207

import java.time.*;

208

import jakarta.ws.rs.*;

209

210

@Path("/global")

211

public class GlobalTimeResource {

212

213

@GET

214

@Path("/meetings")

215

public List<Meeting> getMeetings(@QueryParam("start") OffsetDateTimeParam start,

216

@QueryParam("timezone") ZoneIdParam timezone) {

217

218

OffsetDateTime startTime = start != null ? start.get() : OffsetDateTime.now();

219

ZoneId zone = timezone != null ? timezone.get() : ZoneId.systemDefault();

220

221

return meetingService.getMeetingsInTimezone(startTime, zone);

222

}

223

224

@GET

225

@Path("/schedule/{zone}")

226

public WorkSchedule getScheduleForZone(@PathParam("zone") ZoneIdParam zoneParam,

227

@QueryParam("date") LocalDateParam date) {

228

229

ZoneId zone = zoneParam.get();

230

LocalDate scheduleDate = date != null ? date.get() : LocalDate.now(zone);

231

232

return scheduleService.getScheduleForZone(zone, scheduleDate);

233

}

234

235

@POST

236

@Path("/events")

237

public Response createEvent(@FormParam("startTime") ZonedDateTimeParam startTime,

238

@FormParam("endTime") ZonedDateTimeParam endTime,

239

@Valid CreateEventRequest request) {

240

241

Event event = eventService.createEvent(

242

request,

243

startTime.get(),

244

endTime.get()

245

);

246

247

return Response.status(201).entity(event).build();

248

}

249

}

250

251

// Example URLs:

252

// GET /global/meetings?start=2023-12-25T10:30:00+01:00&timezone=Europe/London

253

// GET /global/schedule/America/New_York?date=2023-12-25

254

```

255

256

### Year and Month Parameters

257

258

Parameter converters for year and year-month values for date range operations.

259

260

```java { .api }

261

/**

262

* Parameter wrapper for Year values

263

* Parses year strings (e.g., "2023")

264

*/

265

public class YearParam extends AbstractParam<Year> {

266

267

/** Creates YearParam from year string */

268

public YearParam(String input);

269

270

/** Creates YearParam with custom parameter name */

271

public YearParam(String input, String parameterName);

272

}

273

274

/**

275

* Parameter wrapper for YearMonth values

276

* Parses year-month strings (e.g., "2023-12")

277

*/

278

public class YearMonthParam extends AbstractParam<YearMonth> {

279

280

/** Creates YearMonthParam from year-month string */

281

public YearMonthParam(String input);

282

283

/** Creates YearMonthParam with custom parameter name */

284

public YearMonthParam(String input, String parameterName);

285

}

286

```

287

288

**Usage Examples:**

289

290

```java

291

import java.time.*;

292

import jakarta.ws.rs.*;

293

294

@Path("/reports")

295

public class ReportsResource {

296

297

@GET

298

@Path("/monthly")

299

public MonthlyReport getMonthlyReport(@QueryParam("month") YearMonthParam month) {

300

YearMonth reportMonth = month != null ? month.get() : YearMonth.now();

301

return reportService.getMonthlyReport(reportMonth);

302

}

303

304

@GET

305

@Path("/yearly")

306

public YearlyReport getYearlyReport(@QueryParam("year") YearParam year) {

307

Year reportYear = year != null ? year.get() : Year.now();

308

return reportService.getYearlyReport(reportYear);

309

}

310

311

@GET

312

@Path("/quarterly")

313

public List<QuarterlyReport> getQuarterlyReports(@QueryParam("year") YearParam year) {

314

Year reportYear = year != null ? year.get() : Year.now();

315

316

return List.of(

317

reportService.getQuarterlyReport(reportYear, 1),

318

reportService.getQuarterlyReport(reportYear, 2),

319

reportService.getQuarterlyReport(reportYear, 3),

320

reportService.getQuarterlyReport(reportYear, 4)

321

);

322

}

323

324

@GET

325

@Path("/range")

326

public Report getReportForRange(@QueryParam("from") YearMonthParam from,

327

@QueryParam("to") YearMonthParam to) {

328

329

YearMonth fromMonth = from != null ? from.get() : YearMonth.now().minusMonths(12);

330

YearMonth toMonth = to != null ? to.get() : YearMonth.now();

331

332

return reportService.getReportForRange(fromMonth, toMonth);

333

}

334

}

335

336

// Example URLs:

337

// GET /reports/monthly?month=2023-12

338

// GET /reports/yearly?year=2023

339

// GET /reports/range?from=2023-01&to=2023-12

340

```

341

342

## Date/Time Patterns and Formats

343

344

### Supported Input Formats

345

346

```java

347

public class DateTimeFormats {

348

349

// InstantParam supports:

350

// "2023-12-25T10:30:00Z"

351

// "2023-12-25T10:30:00.123Z"

352

// "2023-12-25T10:30:00+01:00"

353

354

// InstantSecondParam supports:

355

// "1703505000" (Unix timestamp in seconds)

356

357

// LocalDateParam supports:

358

// "2023-12-25"

359

360

// LocalDateTimeParam supports:

361

// "2023-12-25T10:30:00"

362

// "2023-12-25T10:30:00.123"

363

364

// LocalTimeParam supports:

365

// "10:30:00"

366

// "10:30:00.123"

367

// "10:30"

368

369

// OffsetDateTimeParam supports:

370

// "2023-12-25T10:30:00+01:00"

371

// "2023-12-25T10:30:00-05:00"

372

// "2023-12-25T10:30:00Z"

373

374

// ZonedDateTimeParam supports:

375

// "2023-12-25T10:30:00[Europe/London]"

376

// "2023-12-25T10:30:00+01:00[Europe/London]"

377

378

// ZoneIdParam supports:

379

// "UTC"

380

// "Europe/London"

381

// "America/New_York"

382

// "+01:00"

383

// "-05:00"

384

385

// YearParam supports:

386

// "2023"

387

388

// YearMonthParam supports:

389

// "2023-12"

390

}

391

```

392

393

### Error Handling

394

395

All JSR310 parameter types provide consistent error handling:

396

397

```java

398

@Path("/dates")

399

public class DateErrorHandlingResource {

400

401

@GET

402

public Response getDataForDate(@QueryParam("date") LocalDateParam date) {

403

try {

404

LocalDate actualDate = date.get(); // May throw WebApplicationException

405

Data data = dataService.getDataForDate(actualDate);

406

return Response.ok(data).build();

407

408

} catch (WebApplicationException e) {

409

// Parameter parsing failed - returns 400 Bad Request

410

// Error message will be: "date is not a valid date format"

411

throw e;

412

}

413

}

414

}

415

416

// Invalid input examples that result in 400 errors:

417

// GET /dates?date=invalid-date

418

// GET /dates?date=2023-13-45 (invalid month/day)

419

// GET /dates?date=25-12-2023 (wrong format)

420

```

421

422

## Advanced Usage Patterns

423

424

### Date Range Queries

425

426

```java

427

@Path("/analytics")

428

public class AnalyticsResource {

429

430

@GET

431

@Path("/sales")

432

public SalesReport getSalesReport(@QueryParam("from") LocalDateParam from,

433

@QueryParam("to") LocalDateParam to,

434

@QueryParam("timezone") ZoneIdParam timezone) {

435

436

LocalDate fromDate = from != null ? from.get() : LocalDate.now().minusDays(30);

437

LocalDate toDate = to != null ? to.get() : LocalDate.now();

438

ZoneId zone = timezone != null ? timezone.get() : ZoneId.systemDefault();

439

440

// Convert to start/end of day in specified timezone

441

ZonedDateTime startTime = fromDate.atStartOfDay(zone);

442

ZonedDateTime endTime = toDate.plusDays(1).atStartOfDay(zone);

443

444

return analyticsService.getSalesReport(startTime, endTime);

445

}

446

447

@GET

448

@Path("/activity")

449

public ActivityReport getActivityReport(@QueryParam("month") YearMonthParam month,

450

@QueryParam("timezone") ZoneIdParam timezone) {

451

452

YearMonth reportMonth = month != null ? month.get() : YearMonth.now();

453

ZoneId zone = timezone != null ? timezone.get() : ZoneId.systemDefault();

454

455

// Get first and last day of month in timezone

456

LocalDate firstDay = reportMonth.atDay(1);

457

LocalDate lastDay = reportMonth.atEndOfMonth();

458

459

ZonedDateTime start = firstDay.atStartOfDay(zone);

460

ZonedDateTime end = lastDay.plusDays(1).atStartOfDay(zone);

461

462

return analyticsService.getActivityReport(start, end);

463

}

464

}

465

```

466

467

### Time-based Resource Filtering

468

469

```java

470

@Path("/logs")

471

public class LogResource {

472

473

@GET

474

public List<LogEntry> getLogs(@QueryParam("since") InstantParam since,

475

@QueryParam("level") String level,

476

@QueryParam("limit") Integer limit) {

477

478

Instant sinceTime = since != null ? since.get() : Instant.now().minus(Duration.ofHours(1));

479

int maxResults = limit != null ? limit : 100;

480

481

return logService.getLogs(sinceTime, level, maxResults);

482

}

483

484

@GET

485

@Path("/between")

486

public List<LogEntry> getLogsBetween(@QueryParam("start") InstantParam start,

487

@QueryParam("end") InstantParam end) {

488

489

if (start == null || end == null) {

490

throw new WebApplicationException("Both start and end times are required", 400);

491

}

492

493

Instant startTime = start.get();

494

Instant endTime = end.get();

495

496

if (startTime.isAfter(endTime)) {

497

throw new WebApplicationException("Start time must be before end time", 400);

498

}

499

500

return logService.getLogsBetween(startTime, endTime);

501

}

502

}

503

```

504

505

### Timezone-aware Operations

506

507

```java

508

@Path("/meetings")

509

public class MeetingResource {

510

511

@POST

512

public Response scheduleMeeting(@FormParam("startTime") ZonedDateTimeParam startTime,

513

@FormParam("duration") Integer durationMinutes,

514

@FormParam("attendeeTimezone") ZoneIdParam attendeeZone,

515

@Valid ScheduleMeetingRequest request) {

516

517

ZonedDateTime meetingStart = startTime.get();

518

Duration duration = Duration.ofMinutes(durationMinutes != null ? durationMinutes : 60);

519

ZoneId attendeeTimezone = attendeeZone != null ? attendeeZone.get() : ZoneId.systemDefault();

520

521

// Convert meeting time to attendee's timezone for confirmation

522

ZonedDateTime localStartTime = meetingStart.withZoneSameInstant(attendeeTimezone);

523

524

Meeting meeting = meetingService.scheduleMeeting(

525

request,

526

meetingStart,

527

duration,

528

attendeeTimezone

529

);

530

531

return Response.status(201)

532

.entity(meeting)

533

.header("X-Local-Start-Time", localStartTime.toString())

534

.build();

535

}

536

537

@GET

538

@Path("/availability")

539

public AvailabilityResponse getAvailability(@QueryParam("date") LocalDateParam date,

540

@QueryParam("timezone") ZoneIdParam timezone,

541

@QueryParam("duration") Integer durationMinutes) {

542

543

LocalDate checkDate = date != null ? date.get() : LocalDate.now();

544

ZoneId zone = timezone != null ? timezone.get() : ZoneId.systemDefault();

545

Duration meetingDuration = Duration.ofMinutes(durationMinutes != null ? durationMinutes : 30);

546

547

return meetingService.getAvailability(checkDate, zone, meetingDuration);

548

}

549

}

550

```

551

552

## Best Practices

553

554

### Parameter Validation

555

556

```java

557

@Path("/validation")

558

public class DateValidationResource {

559

560

@GET

561

@Path("/future-events")

562

public List<Event> getFutureEvents(@QueryParam("from") LocalDateParam from) {

563

564

LocalDate fromDate = from != null ? from.get() : LocalDate.now();

565

566

// Validate that date is not too far in the past

567

if (fromDate.isBefore(LocalDate.now().minusYears(1))) {

568

throw new WebApplicationException("Date cannot be more than 1 year in the past", 400);

569

}

570

571

// Validate that date is not too far in the future

572

if (fromDate.isAfter(LocalDate.now().plusYears(5))) {

573

throw new WebApplicationException("Date cannot be more than 5 years in the future", 400);

574

}

575

576

return eventService.getFutureEventsFrom(fromDate);

577

}

578

579

@GET

580

@Path("/business-hours")

581

public List<Appointment> getBusinessHourAppointments(@QueryParam("date") LocalDateParam date,

582

@QueryParam("startTime") LocalTimeParam startTime) {

583

584

LocalDate appointmentDate = date != null ? date.get() : LocalDate.now();

585

LocalTime start = startTime != null ? startTime.get() : LocalTime.of(9, 0);

586

587

// Validate business hours

588

if (start.isBefore(LocalTime.of(8, 0)) || start.isAfter(LocalTime.of(18, 0))) {

589

throw new WebApplicationException("Start time must be between 08:00 and 18:00", 400);

590

}

591

592

return appointmentService.getAppointments(appointmentDate, start);

593

}

594

}

595

```

596

597

### Default Values and Null Handling

598

599

```java

600

@Path("/defaults")

601

public class DefaultDateResource {

602

603

@GET

604

@Path("/recent")

605

public List<Item> getRecentItems(@QueryParam("since") InstantParam since) {

606

// Provide sensible default if parameter not provided

607

Instant sinceTime = since != null ? since.get() : Instant.now().minus(Duration.ofDays(7));

608

return itemService.getItemsSince(sinceTime);

609

}

610

611

@GET

612

@Path("/monthly/{year}")

613

public MonthlyData getMonthlyData(@PathParam("year") YearParam year,

614

@QueryParam("month") Integer month) {

615

616

Year dataYear = year.get(); // Required path parameter

617

618

// Handle optional month parameter

619

YearMonth yearMonth;

620

if (month != null && month >= 1 && month <= 12) {

621

yearMonth = YearMonth.of(dataYear.getValue(), month);

622

} else {

623

yearMonth = YearMonth.now();

624

}

625

626

return dataService.getMonthlyData(yearMonth);

627

}

628

}

629

```