or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

arithmetic.mdformatting.mdindex.mdinstant.mdlocal-types.mdplatform.mdranges.mdserialization.mdtimezones.md

formatting.mddocs/

0

# Formatting and Parsing System

1

2

Comprehensive formatting and parsing system with DSL builders for creating custom date/time formats. The library supports ISO 8601 formats out of the box and provides flexible builders for custom formatting needs.

3

4

## Capabilities

5

6

### DateTimeFormat<T>

7

8

Core formatting interface that handles both parsing and formatting of date/time values.

9

10

```kotlin { .api }

11

/**

12

* Format for parsing and formatting date/time values

13

* Sealed interface providing type-safe formatting operations

14

*/

15

sealed interface DateTimeFormat<T> {

16

/**

17

* Format a value to string

18

* @param value The value to format

19

* @returns Formatted string representation

20

*/

21

fun format(value: T): String

22

23

/**

24

* Format a value to an appendable

25

* @param appendable Target to append the formatted value to

26

* @param value The value to format

27

* @returns The appendable for chaining

28

*/

29

fun formatTo(appendable: Appendable, value: T): Appendable

30

31

/**

32

* Parse a string to the target type

33

* @param input String to parse

34

* @returns Parsed value

35

* @throws DateTimeParseException if parsing fails

36

*/

37

fun parse(input: CharSequence): T

38

39

/**

40

* Parse a string to the target type, returning null on failure

41

* @param input String to parse

42

* @returns Parsed value or null if parsing fails

43

*/

44

fun parseOrNull(input: CharSequence): T?

45

46

companion object {

47

/**

48

* Generate Kotlin DSL code for recreating a format

49

* @param format The format to analyze

50

* @returns Kotlin code string

51

*/

52

fun formatAsKotlinBuilderDsl(format: DateTimeFormat<*>): String

53

}

54

}

55

```

56

57

**Usage Examples:**

58

59

```kotlin

60

import kotlinx.datetime.*

61

62

// Using predefined formats

63

val date = LocalDate(2023, 12, 25)

64

val formatted = date.format(LocalDate.Formats.ISO) // "2023-12-25"

65

66

// Parse from string

67

val parsed = LocalDate.parse("2023-12-25", LocalDate.Formats.ISO)

68

69

// Safe parsing

70

val maybeParsed = LocalDate.Formats.ISO.parseOrNull("invalid-date") // null

71

72

// Format to StringBuilder

73

val buffer = StringBuilder()

74

LocalDate.Formats.ISO.formatTo(buffer, date)

75

println(buffer.toString()) // "2023-12-25"

76

```

77

78

### Predefined Formats

79

80

Each date/time type provides predefined format constants for common use cases.

81

82

#### LocalDate Formats

83

84

```kotlin { .api }

85

object LocalDate.Formats {

86

/** ISO 8601 extended format: YYYY-MM-DD */

87

val ISO: DateTimeFormat<LocalDate>

88

89

/** ISO 8601 basic format: YYYYMMDD */

90

val ISO_BASIC: DateTimeFormat<LocalDate>

91

}

92

```

93

94

#### LocalTime Formats

95

96

```kotlin { .api }

97

object LocalTime.Formats {

98

/** ISO 8601 extended format: HH:MM:SS[.fff] */

99

val ISO: DateTimeFormat<LocalTime>

100

}

101

```

102

103

#### LocalDateTime Formats

104

105

```kotlin { .api }

106

object LocalDateTime.Formats {

107

/** ISO 8601 extended format: YYYY-MM-DDTHH:MM:SS[.fff] */

108

val ISO: DateTimeFormat<LocalDateTime>

109

}

110

```

111

112

#### YearMonth Formats

113

114

```kotlin { .api }

115

object YearMonth.Formats {

116

/** ISO 8601 extended format: YYYY-MM */

117

val ISO: DateTimeFormat<YearMonth>

118

}

119

```

120

121

#### UtcOffset Formats

122

123

```kotlin { .api }

124

object UtcOffset.Formats {

125

/** ISO 8601 extended format: +HH:MM, +HH:MM:SS, or Z */

126

val ISO: DateTimeFormat<UtcOffset>

127

128

/** ISO 8601 basic format: +HHMM, +HHMMSS, or Z */

129

val ISO_BASIC: DateTimeFormat<UtcOffset>

130

131

/** Four digits format: always ±HHMM, never Z */

132

val FOUR_DIGITS: DateTimeFormat<UtcOffset>

133

}

134

```

135

136

**Usage Examples:**

137

138

```kotlin

139

import kotlinx.datetime.*

140

141

val date = LocalDate(2023, 12, 25)

142

val time = LocalTime(15, 30, 45, 123456789)

143

val dateTime = LocalDateTime(date, time)

144

val yearMonth = YearMonth(2023, 12)

145

val offset = UtcOffset(hours = 5, minutes = 30)

146

147

// Format using predefined formats

148

println(date.format(LocalDate.Formats.ISO)) // "2023-12-25"

149

println(date.format(LocalDate.Formats.ISO_BASIC)) // "20231225"

150

println(time.format(LocalTime.Formats.ISO)) // "15:30:45.123456789"

151

println(dateTime.format(LocalDateTime.Formats.ISO)) // "2023-12-25T15:30:45.123456789"

152

println(yearMonth.format(YearMonth.Formats.ISO)) // "2023-12"

153

println(offset.format(UtcOffset.Formats.ISO)) // "+05:30"

154

println(offset.format(UtcOffset.Formats.ISO_BASIC)) // "+0530"

155

println(offset.format(UtcOffset.Formats.FOUR_DIGITS)) // "+0530"

156

157

// Parse using predefined formats

158

val parsedDate = LocalDate.parse("2023-12-25", LocalDate.Formats.ISO)

159

val parsedTime = LocalTime.parse("15:30:45", LocalTime.Formats.ISO)

160

val parsedOffset = UtcOffset.parse("+05:30", UtcOffset.Formats.ISO)

161

```

162

163

### DateTimeFormatBuilder DSL

164

165

Flexible DSL for creating custom date/time formats with fine-grained control over each component.

166

167

#### Base Builder Interface

168

169

```kotlin { .api }

170

/**

171

* Base interface for all format builders

172

* Provides common formatting operations

173

*/

174

interface DateTimeFormatBuilder {

175

/**

176

* Add literal text to the format

177

* @param value Literal string to include

178

*/

179

fun chars(value: String)

180

181

/**

182

* Add a single literal character

183

* @param value Character to include

184

*/

185

fun char(value: Char)

186

}

187

```

188

189

#### Date Component Builders

190

191

```kotlin { .api }

192

/**

193

* Builder for formats that include date components

194

*/

195

interface DateTimeFormatBuilder.WithDate : DateTimeFormatBuilder {

196

/**

197

* Year component

198

* @param padding Padding style for the year

199

*/

200

fun year(padding: Padding = Padding.ZERO)

201

202

/**

203

* Month as number

204

* @param padding Padding style (NONE, ZERO, SPACE)

205

*/

206

fun monthNumber(padding: Padding = Padding.ZERO)

207

208

/**

209

* Day of month

210

* @param padding Padding style

211

*/

212

fun dayOfMonth(padding: Padding = Padding.ZERO)

213

214

/**

215

* Day of year (1-366)

216

* @param padding Padding style

217

*/

218

fun dayOfYear(padding: Padding = Padding.ZERO)

219

220

/**

221

* Day of week as number (1=Monday, 7=Sunday)

222

* @param padding Padding style

223

*/

224

fun dayOfWeek(padding: Padding = Padding.ZERO)

225

}

226

```

227

228

#### Time Component Builders

229

230

```kotlin { .api }

231

/**

232

* Builder for formats that include time components

233

*/

234

interface DateTimeFormatBuilder.WithTime : DateTimeFormatBuilder {

235

/**

236

* Hour component (0-23)

237

* @param padding Padding style

238

*/

239

fun hour(padding: Padding = Padding.ZERO)

240

241

/**

242

* Minute component (0-59)

243

* @param padding Padding style

244

*/

245

fun minute(padding: Padding = Padding.ZERO)

246

247

/**

248

* Second component (0-59)

249

* @param padding Padding style

250

*/

251

fun second(padding: Padding = Padding.ZERO)

252

253

/**

254

* Fractional second component

255

* @param minLength Minimum number of digits

256

* @param maxLength Maximum number of digits

257

*/

258

fun secondFraction(minLength: Int = 0, maxLength: Int = 9)

259

260

/**

261

* AM/PM marker

262

* @param am String for AM (default "AM")

263

* @param pm String for PM (default "PM")

264

*/

265

fun amPmMarker(am: String = "AM", pm: String = "PM")

266

}

267

```

268

269

#### Combined Builders

270

271

```kotlin { .api }

272

/**

273

* Builder for formats with both date and time components

274

*/

275

interface DateTimeFormatBuilder.WithDateTime :

276

DateTimeFormatBuilder.WithDate,

277

DateTimeFormatBuilder.WithTime

278

279

/**

280

* Builder for formats with UTC offset

281

*/

282

interface DateTimeFormatBuilder.WithUtcOffset : DateTimeFormatBuilder {

283

/**

284

* UTC offset component

285

* @param format Offset format style

286

*/

287

fun offset(format: UtcOffsetFormat)

288

}

289

290

/**

291

* Builder for YearMonth formats

292

*/

293

interface DateTimeFormatBuilder.WithYearMonth : DateTimeFormatBuilder {

294

fun year(padding: Padding = Padding.ZERO)

295

fun monthNumber(padding: Padding = Padding.ZERO)

296

}

297

```

298

299

#### Padding Enumeration

300

301

```kotlin { .api }

302

/**

303

* Padding style for formatting numeric components

304

*/

305

enum class Padding {

306

/** No padding */

307

NONE,

308

309

/** Pad with zeros */

310

ZERO,

311

312

/** Pad with spaces */

313

SPACE

314

}

315

```

316

317

### Format Builder Functions

318

319

Factory functions for creating custom formats using the DSL.

320

321

```kotlin { .api }

322

/**

323

* Create a LocalDate format using the DSL

324

* @param builder DSL builder function

325

* @returns DateTimeFormat for LocalDate

326

*/

327

fun LocalDate.Format(

328

builder: DateTimeFormatBuilder.WithDate.() -> Unit

329

): DateTimeFormat<LocalDate>

330

331

/**

332

* Create a LocalTime format using the DSL

333

* @param builder DSL builder function

334

* @returns DateTimeFormat for LocalTime

335

*/

336

fun LocalTime.Format(

337

builder: DateTimeFormatBuilder.WithTime.() -> Unit

338

): DateTimeFormat<LocalTime>

339

340

/**

341

* Create a LocalDateTime format using the DSL

342

* @param builder DSL builder function

343

* @returns DateTimeFormat for LocalDateTime

344

*/

345

fun LocalDateTime.Format(

346

builder: DateTimeFormatBuilder.WithDateTime.() -> Unit

347

): DateTimeFormat<LocalDateTime>

348

349

/**

350

* Create a YearMonth format using the DSL

351

* @param builder DSL builder function

352

* @returns DateTimeFormat for YearMonth

353

*/

354

fun YearMonth.Format(

355

builder: DateTimeFormatBuilder.WithYearMonth.() -> Unit

356

): DateTimeFormat<YearMonth>

357

358

/**

359

* Create a UtcOffset format using the DSL

360

* @param builder DSL builder function

361

* @returns DateTimeFormat for UtcOffset

362

*/

363

fun UtcOffset.Format(

364

builder: DateTimeFormatBuilder.WithUtcOffset.() -> Unit

365

): DateTimeFormat<UtcOffset>

366

367

/**

368

* Create a DateTimeComponents format using the DSL

369

* @param builder DSL builder function

370

* @returns DateTimeFormat for DateTimeComponents

371

*/

372

fun DateTimeComponents.Format(

373

builder: DateTimeFormatBuilder.WithDateTime.() -> Unit

374

): DateTimeFormat<DateTimeComponents>

375

```

376

377

**Usage Examples:**

378

379

```kotlin

380

import kotlinx.datetime.*

381

382

// Custom LocalDate format: "25/12/2023"

383

val customDateFormat = LocalDate.Format {

384

dayOfMonth()

385

char('/')

386

monthNumber()

387

char('/')

388

year()

389

}

390

391

val date = LocalDate(2023, 12, 25)

392

println(date.format(customDateFormat)) // "25/12/2023"

393

394

// Custom LocalTime format: "3:30:45 PM"

395

val customTimeFormat = LocalTime.Format {

396

hour(padding = Padding.NONE) // No leading zero

397

char(':')

398

minute()

399

char(':')

400

second()

401

char(' ')

402

amPmMarker()

403

}

404

405

val time = LocalTime(15, 30, 45)

406

println(time.format(customTimeFormat)) // "3:30:45 PM"

407

408

// Custom LocalDateTime format with milliseconds: "2023-12-25 15:30:45.123"

409

val customDateTimeFormat = LocalDateTime.Format {

410

year()

411

char('-')

412

monthNumber()

413

char('-')

414

dayOfMonth()

415

char(' ')

416

hour()

417

char(':')

418

minute()

419

char(':')

420

second()

421

char('.')

422

secondFraction(minLength = 3, maxLength = 3) // Always 3 digits

423

}

424

425

val dateTime = LocalDateTime(2023, 12, 25, 15, 30, 45, 123000000)

426

println(dateTime.format(customDateTimeFormat)) // "2023-12-25 15:30:45.123"

427

428

// Complex format with day of week: "Monday, December 25, 2023"

429

val verboseFormat = LocalDate.Format {

430

// Note: This would require additional enum formatting support

431

monthNumber() // Would need month name support in actual implementation

432

char(' ')

433

dayOfMonth()

434

chars(", ")

435

year()

436

}

437

```

438

439

### DateTimeComponents

440

441

Container class for holding individual date/time components during formatting operations.

442

443

```kotlin { .api }

444

/**

445

* Container for date/time components used in formatting

446

* Holds individual components that can be formatted independently

447

*/

448

class DateTimeComponents {

449

// Date components

450

var year: Int?

451

var month: Int?

452

var dayOfMonth: Int?

453

var dayOfYear: Int?

454

var dayOfWeek: Int?

455

456

// Time components

457

var hour: Int?

458

var minute: Int?

459

var second: Int?

460

var nanosecond: Int?

461

462

// Offset component

463

var offsetSeconds: Int?

464

465

/**

466

* Convert to LocalDate if date components are available

467

* @returns LocalDate or null if insufficient components

468

*/

469

fun toLocalDate(): LocalDate?

470

471

/**

472

* Convert to LocalTime if time components are available

473

* @returns LocalTime or null if insufficient components

474

*/

475

fun toLocalTime(): LocalTime?

476

477

/**

478

* Convert to LocalDateTime if date and time components are available

479

* @returns LocalDateTime or null if insufficient components

480

*/

481

fun toLocalDateTime(): LocalDateTime?

482

483

/**

484

* Convert to UtcOffset if offset component is available

485

* @returns UtcOffset or null if offset not set

486

*/

487

fun toUtcOffset(): UtcOffset?

488

}

489

```

490

491

### Instant Formatting

492

493

Special formatting for Instant values that require offset specification.

494

495

```kotlin { .api }

496

/**

497

* Format an Instant using DateTimeComponents format with specified offset

498

* @param format DateTimeComponents format to use

499

* @param offset UTC offset for formatting the instant

500

* @returns Formatted string

501

*/

502

fun Instant.format(format: DateTimeFormat<DateTimeComponents>, offset: UtcOffset): String

503

504

/**

505

* Parse an Instant from string using DateTimeComponents format

506

* @param input String to parse

507

* @param format DateTimeComponents format to use

508

* @returns Parsed Instant

509

*/

510

fun Instant.Companion.parse(input: CharSequence, format: DateTimeFormat<DateTimeComponents>): Instant

511

```

512

513

**Usage Examples:**

514

515

```kotlin

516

import kotlinx.datetime.*

517

import kotlin.time.Clock

518

519

// Create a custom format for Instant

520

val instantFormat = DateTimeComponents.Format {

521

year()

522

char('-')

523

monthNumber()

524

char('-')

525

dayOfMonth()

526

char('T')

527

hour()

528

char(':')

529

minute()

530

char(':')

531

second()

532

offset(UtcOffsetFormat.ISO)

533

}

534

535

val now = Clock.System.now()

536

val offset = UtcOffset(hours = 5, minutes = 30)

537

538

// Format instant with offset

539

val formatted = now.format(instantFormat, offset)

540

println(formatted) // "2023-12-25T20:30:45+05:30"

541

542

// Parse back to instant

543

val parsed = Instant.parse(formatted, instantFormat)

544

```

545

546

## Advanced Formatting Patterns

547

548

### Conditional Formatting

549

550

```kotlin

551

import kotlinx.datetime.*

552

553

// Format that shows seconds only when non-zero

554

val conditionalTimeFormat = LocalTime.Format {

555

hour()

556

char(':')

557

minute()

558

// In a real implementation, this would need conditional support

559

// Currently not directly supported, would need custom format implementation

560

}

561

562

// Work around with multiple formats for different cases

563

val timeWithSeconds = LocalTime.Format {

564

hour()

565

char(':')

566

minute()

567

char(':')

568

second()

569

}

570

571

val timeWithoutSeconds = LocalTime.Format {

572

hour()

573

char(':')

574

minute()

575

}

576

577

fun formatTimeConditionally(time: LocalTime): String {

578

return if (time.second == 0 && time.nanosecond == 0) {

579

time.format(timeWithoutSeconds)

580

} else {

581

time.format(timeWithSeconds)

582

}

583

}

584

585

val time1 = LocalTime(15, 30) // No seconds

586

val time2 = LocalTime(15, 30, 45) // Has seconds

587

588

println(formatTimeConditionally(time1)) // "15:30"

589

println(formatTimeConditionally(time2)) // "15:30:45"

590

```

591

592

### Localized Formatting

593

594

While the core library focuses on ISO formats, custom localized formats can be created:

595

596

```kotlin

597

import kotlinx.datetime.*

598

599

// German date format: DD.MM.YYYY

600

val germanDateFormat = LocalDate.Format {

601

dayOfMonth()

602

char('.')

603

monthNumber()

604

char('.')

605

year()

606

}

607

608

// US date format: MM/DD/YYYY

609

val usDateFormat = LocalDate.Format {

610

monthNumber()

611

char('/')

612

dayOfMonth()

613

char('/')

614

year()

615

}

616

617

val date = LocalDate(2023, 12, 25)

618

println("German: ${date.format(germanDateFormat)}") // "25.12.2023"

619

println("US: ${date.format(usDateFormat)}") // "12/25/2023"

620

621

// 24-hour vs 12-hour time

622

val time24Format = LocalTime.Format {

623

hour()

624

char(':')

625

minute()

626

}

627

628

val time12Format = LocalTime.Format {

629

hour() // Would need 12-hour conversion logic

630

char(':')

631

minute()

632

char(' ')

633

amPmMarker()

634

}

635

636

val time = LocalTime(15, 30)

637

println("24-hour: ${time.format(time24Format)}") // "15:30"

638

// 12-hour would need additional conversion logic

639

```

640

641

### Complex Date Formats

642

643

```kotlin

644

import kotlinx.datetime.*

645

646

// ISO week date format (would need additional support)

647

val isoWeekFormat = LocalDate.Format {

648

year()

649

char('-')

650

chars("W")

651

// Would need week-of-year support

652

dayOfWeek()

653

}

654

655

// Ordinal date format: YYYY-DDD

656

val ordinalFormat = LocalDate.Format {

657

year()

658

char('-')

659

dayOfYear(padding = Padding.ZERO) // Pad to 3 digits

660

}

661

662

val date = LocalDate(2023, 12, 25)

663

println("Ordinal: ${date.format(ordinalFormat)}") // "2023-359"

664

665

// Custom verbose format with literals

666

val verboseFormat = LocalDate.Format {

667

chars("Year ")

668

year()

669

chars(", Month ")

670

monthNumber()

671

chars(", Day ")

672

dayOfMonth()

673

}

674

675

println("Verbose: ${date.format(verboseFormat)}") // "Year 2023, Month 12, Day 25"

676

```

677

678

## Error Handling

679

680

Parsing operations can fail and throw exceptions:

681

682

```kotlin { .api }

683

/**

684

* Thrown when date/time parsing fails

685

*/

686

class DateTimeParseException : RuntimeException {

687

constructor(message: String)

688

constructor(message: String, cause: Throwable?)

689

}

690

```

691

692

**Error Handling Examples:**

693

694

```kotlin

695

import kotlinx.datetime.*

696

697

val format = LocalDate.Format {

698

year()

699

char('-')

700

monthNumber()

701

char('-')

702

dayOfMonth()

703

}

704

705

// Safe parsing

706

val input = "2023-13-45" // Invalid date

707

val result = format.parseOrNull(input) // Returns null instead of throwing

708

709

if (result == null) {

710

println("Failed to parse: $input")

711

} else {

712

println("Parsed: $result")

713

}

714

715

// Exception-based parsing

716

try {

717

val parsed = format.parse(input)

718

println("Parsed: $parsed")

719

} catch (e: DateTimeParseException) {

720

println("Parse error: ${e.message}")

721

}

722

723

// Validate format before parsing

724

fun safeParse(input: String, format: DateTimeFormat<LocalDate>): LocalDate? {

725

return try {

726

format.parse(input)

727

} catch (e: Exception) {

728

null

729

}

730

}

731

```

732

733

## Format Debugging

734

735

Generate DSL code for existing formats:

736

737

```kotlin

738

import kotlinx.datetime.*

739

740

// Generate code for predefined format

741

val isoCode = DateTimeFormat.formatAsKotlinBuilderDsl(LocalDate.Formats.ISO)

742

println("ISO format DSL:")

743

println(isoCode)

744

745

// This would output something like:

746

// LocalDate.Format {

747

// year()

748

// char('-')

749

// monthNumber()

750

// char('-')

751

// dayOfMonth()

752

// }

753

```