blob: e47c2cb7bda7ef31ce9c52ea330d5b7ba5facf33 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of intl;
/**
* A class for holding onto the data for a date so that it can be built
* up incrementally.
*/
class _DateBuilder {
// Default the date values to the EPOCH so that there's a valid date
// in case the format doesn't set them.
int year = 1970,
month = 1,
day = 1,
hour = 0,
minute = 0,
second = 0,
fractionalSecond = 0;
bool pm = false;
bool utc = false;
// Functions that exist just to be closurized so we can pass them to a general
// method.
void setYear(x) { year = x; }
void setMonth(x) { month = x; }
void setDay(x) { day = x; }
void setHour(x) { hour = x; }
void setMinute(x) { minute = x; }
void setSecond(x) { second = x; }
void setFractionalSecond(x) { fractionalSecond = x; }
/**
* Return a date built using our values. If no date portion is set,
* use the "Epoch" of January 1, 1970.
*/
Date asDate() {
// TODO(alanknight): Validate the date, especially for things which
// can crash the VM, e.g. large month values.
if (utc) {
return new Date.utc(
year,
month,
day,
pm ? hour + 12 : hour,
minute,
second,
fractionalSecond);
} else {
return new Date(
year,
month,
day,
pm ? hour + 12 : hour,
minute,
second,
fractionalSecond);
}
}
}
/**
* A simple and not particularly general stream class to make parsing
* dates from strings simpler. It is general enough to operate on either
* lists or strings.
*/
class _Stream {
var contents;
int index = 0;
_Stream(this.contents);
bool atEnd() => index >= contents.length;
next() => contents[index++];
/**
* Return the next [howMany] items, or as many as there are remaining.
* Advance the stream by that many positions.
*/
read([howMany = 1]) {
var result = peek(howMany);
index += howMany;
return result;
}
/**
* Return the next [howMany] items, or as many as there are remaining.
* Does not modify the stream position.
*/
peek([howMany = 1]) {
var result;
if (contents is String) {
result = contents.substring(
index,
min(index + howMany, contents.length));
} else {
// Assume List
result = contents.getRange(index, howMany);
}
return result;
}
/** Return the remaining contents of the stream */
rest() => peek(contents.length - index);
/**
* Find the index of the first element for which [f] returns true.
* Advances the stream to that position.
*/
int findIndex(Function f) {
while (!atEnd()) {
if (f(next())) return index - 1;
}
return null;
}
/**
* Find the indexes of all the elements for which [f] returns true.
* Leaves the stream positioned at the end.
*/
List findIndexes(Function f) {
var results = [];
while (!atEnd()) {
if (f(next())) results.add(index - 1);
}
return results;
}
/**
* Assuming that the contents are characters, read as many digits as we
* can see and then return the corresponding integer. Advance the stream.
*/
var digitMatcher = new RegExp(r'\d+');
int nextInteger() {
var string = digitMatcher.stringMatch(rest());
if (string == null || string.isEmpty) return null;
read(string.length);
return int.parse(string);
}
}