Flutter - Number Format - flutter

Is there a way to format a number :
from 1 to 1.00,
from 2.5 to 2.50,
from 2.1234 to 2.1234
so basically the number will have a minimum of 2 decimal places
Thanks for your help.

A non elegant way using Intl package:
var f = NumberFormat('#.00###############', 'en_Us');
print(f.format(2.123400))
and you will get
2.1234
but if your number have more decimal digit than you have '#' in format string then it's not show.
For example
var f = NumberFormat('#.00##', 'en_Us');
print(f.format(2.123456))
you will get
2.1234
I think that way works most of cases.
Or you can make format function by yourself. Like this:
String formatNumber(double number) {
int precision = 0;
while ((number * pow(10, precision)) % 10 != 0) {
precision++;
}
return number.toStringAsFixed(max(precision - 1, 2));
}
In this case you don't use Intl package. There is no problem with number of digit after dot. BUT i belive that is a much slower than using intl package.

The Intl package has a set of formatting classes than can help with this use case in particular the NumberFormat Class

you can use someDoubleValue.toStringAsFixed(2) what this does is it basically adds or removes floating points from value
Note: if you parse double from this result string again, it will convert back (5.00 => 5)
Example:
String parseNumber(value) {
String strValue = value.toString();
List parsedNumber = strValue.split(".");
String newValue;
if (parsedNumber.length == 1) {
newValue = value.toStringAsFixed(2);
} else {
String decimalPlace = parsedNumber[1];
if (decimalPlace.length > 2) {
newValue = value.toString();
} else {
newValue = value.toStringAsFixed(2);
}
}
return newValue;
}

Related

Neatly parsing a date in "MMddyy" format along with other formats in dart

I guess it is not possible to parse a date in "MMddyy" format in dart.
void main() {
String strcandidate = "031623";
String format = "MMddyy";
var originalFormat = DateFormat(format).parse(strcandidate);
}
Output:
Uncaught Error: FormatException: Trying to read dd from 031623 at position 6
The following works fine when parsing a date in "MM-dd-yy" format.
void main() {
String strcandidate = "03-16-23";
String format = "MM-dd-yy";
var originalFormat = DateFormat(format).parse(strcandidate);
}
In the problem, the input date string can be in any format e.g ['yyyy-MM-dd', 'MMM'-yyyy, 'MM/dd/yy']. I am parsing the input string for these formats in a loop as follows.
dateFormatsList = ['yyyy-MM-dd', 'MMM'-yyyy, 'MM/dd/yy'];
for (String format in dateFormatsList ) {
try {
originalFormat = DateFormat(format).parse(strcandidate);
dateFound = true;
} catch (e) {}
}
Adding 'MMddyy' to dateFormatsList is not going to work.
But regular expression be used to parse this format.
However if all formats are parsed using parse method and one additional format is parsed using regular expression, then the code is not that neat, and cluttered.
To write as much neat and efficient code as possible, if you want, you can share your insights about any possibility for making it efficient and clean while incorporating 'MMddyy'format. Tysm!
See How do I convert a date/time string to a DateTime object in Dart? for how to parse various date/time strings to DateTime objects.
If you need to mix approaches, you can provide a unified interface. Instead of using a List<String> for your list of formats, you can use a List<DateTime Function(String)>:
import 'package:intl/intl.dart';
/// Parses a [DateTime] from [dateTimeString] using a [RegExp].
///
/// [re] must have named groups with names `year`, `month`, and `day`.
DateTime parseDateFromRegExp(RegExp re, String dateTimeString) {
var match = re.firstMatch(dateTimeString);
if (match == null) {
throw FormatException('Failed to parse: $dateTimeString');
}
var year = match.namedGroup('year');
var month = match.namedGroup('month');
var day = match.namedGroup('day');
if (year == null || month == null || day == null) {
throw ArgumentError('Regular expression is malformed');
}
// In case we're parsing a two-digit year format, instead of
// parsing the strings ourselves, reparse it with [DateFormat] so that it can
// apply its -80/+20 rule.
//
// [DateFormat.parse] doesn't work without separators, which is why we
// can't use directly on the original string. See:
// https://github.com/dart-lang/intl/issues/210
return DateFormat('yy-MM-dd').parse('$year-$month-$day');
}
typedef DateParser = DateTime Function(String);
DateParser dateParserFromRegExp(String rePattern) =>
(string) => parseDateFromRegExp(RegExp(rePattern), string);
var parserList = [
DateFormat('yyyy-MM-dd').parse,
DateFormat('MMM-yyyy').parse,
DateFormat('MM/dd/yy').parse,
dateParserFromRegExp(
r'^(?<month>\d{2})(?<day>\d{2})(?<year>\d{4})$',
)
];
void main() {
var strcandidate = '12311776';
DateTime? originalFormat;
for (var tryParse in parserList) {
try {
originalFormat = tryParse(strcandidate);
break;
} on Exception {
// Try the next format.
}
}
print(originalFormat);
}
I think it's a bit hacky but what about use a regular expression (RegExp) to parse the date divider and then replace it with just ""?
void main() {
String strcandidate = "031623";
String strYear = strcandidate.substring(4);
//Taken 20 as the year like 2023 as year is in 2 digits
String _newDateTime = '20' + strYear + strcandidate.substring(0, 4);
var _originalFormat = DateTime.parse(_newDateTime);
print(_originalFormat);
}
add the intl to yaml then write this code:
import 'package:intl/intl.dart';
void main() {
var strcandidate = DateTime(2023, 3, 16);
String format = "MMddyy";
var originalFormat = DateFormat(format).format(strcandidate);
print(originalFormat);
}

How to create a spacing between digits in String(format: "%.f") like in calculator App in swift UI

How can i organise my string so it will look nearly like an original calculator. Basically curerntly i am using a string int he following format (String(format: "%.f")
My code Below
mutating func appendNumber(_ number: Double) {
if number.truncatingRemainder(dividingBy: 1) == 0 && currentNumber.truncatingRemainder(dividingBy: 1) == 0 {
currentNumber = 10 * currentNumber + number
} else {
currentNumber = number
}
}
}
struct Home: View {
let characterLimit = 9
//MARK: - Computed propety
var displayedString: String {
return String(String(format: "%.01f",
arguments: [state.currentNumber]).prefix(characterLimit))
}
I want it to have a spacing every 3 characters same as in the native calculator app from IOS.
You should use a NumberFormatter. Example:
var displayedString: String {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return String((formatter.string(for: state.currentNumber) ?? "").prefix(characterLimit))
}
Note that the output is locale dependent. In one locale, it could output 123,456,789. In another locale, it could be 123 456 789, and in a third, it could be 123.456.789. I'm pretty sure there are locales that use different group sizes. The Calculator app has this behaviour too. For the Calculator app on my phone for example, it uses commas, not spaces, as the separator.
If you want to use spaces every 3 digits for the grouping no matter where the phone's locale is set to, you can set it manually:
formatter.groupingSeparator = " "
formatter.groupingSize = 3

Flutter Parse Method Explanation

I have a String date in format Month-Day-4DigitYear that I want to convert to DateTime in Flutter. I'm a novice coder, and I'm struggling to understand the api.flutter.dev Parse method example.
Below is the example. I just have a few issues. Android Studio throws multiple errors when I just create a class and put in this function. I think I understand the non-nullable issue, so I delete the ! and ? marks everywhere.
My issues are: what are _parseFormat, _brokenDownDateToValue, _withValue ?
All give errors and just declaring the first two and deleting the _withValue doesn't seem to do the trick, although removes all errors. It's like they've left out a key portion that I'm missing or there is a package I need to import the neither I nor Android Studio knows about. Can anyone decrypt this? I get very frustrated with flutter's documentation, as it always seems to give 80% of required info, assuming you already are clairvoyant on all other topics except this single one they are discussing. Gotta be a pro before reading the manual.
// TODO(lrn): restrict incorrect values like 2003-02-29T50:70:80.
// Or not, that may be a breaking change.
static DateTime parse(String formattedString) {
var re = _parseFormat;
Match? match = re.firstMatch(formattedString);
if (match != null) {
int parseIntOrZero(String? matched) {
if (matched == null) return 0;
return int.parse(matched);
}
// Parses fractional second digits of '.(\d+)' into the combined
// microseconds. We only use the first 6 digits because of DateTime
// precision of 999 milliseconds and 999 microseconds.
int parseMilliAndMicroseconds(String? matched) {
if (matched == null) return 0;
int length = matched.length;
assert(length >= 1);
int result = 0;
for (int i = 0; i < 6; i++) {
result *= 10;
if (i < matched.length) {
result += matched.codeUnitAt(i) ^ 0x30;
}
}
return result;
}
int years = int.parse(match[1]!);
int month = int.parse(match[2]!);
int day = int.parse(match[3]!);
int hour = parseIntOrZero(match[4]);
int minute = parseIntOrZero(match[5]);
int second = parseIntOrZero(match[6]);
int milliAndMicroseconds = parseMilliAndMicroseconds(match[7]);
int millisecond =
milliAndMicroseconds ~/ Duration.microsecondsPerMillisecond;
int microsecond = milliAndMicroseconds
.remainder(Duration.microsecondsPerMillisecond) as int;
bool isUtc = false;
if (match[8] != null) {
// timezone part
isUtc = true;
String? tzSign = match[9];
if (tzSign != null) {
// timezone other than 'Z' and 'z'.
int sign = (tzSign == '-') ? -1 : 1;
int hourDifference = int.parse(match[10]!);
int minuteDifference = parseIntOrZero(match[11]);
minuteDifference += 60 * hourDifference;
minute -= sign * minuteDifference;
}
}
int? value = _brokenDownDateToValue(years, month, day, hour, minute,
second, millisecond, microsecond, isUtc);
if (value == null) {
throw FormatException("Time out of range", formattedString);
}
return DateTime._withValue(value, isUtc: isUtc);
} else {
throw FormatException("Invalid date format", formattedString);
}
}
My issues are: what are _parseFormat, _brokenDownDateToValue, _withValue ?
These are objects or functions declared elsewhere in the lib which are private (the _ as the first character declares objects and functions as private) and therefore not shown in the documentation.
_parseFormat seems to be a regular expression.
_brokenDownDateToValue seems to be a function.
_withValue is a named constructor.
I think what you want to use is the following if you want to parse your date String to a DateTime object.
var date = "11-28-2020"; // Month-Day-4DigitYear
var dateTime = DateTime.parse(date.split('-').reversed.join());
See https://api.flutter.dev/flutter/dart-core/DateTime/parse.html for the accepted strings to be parsed.
I did find the full code example here.
It didn't use the name _parseFormat, instead just RegExp? And has _withValue and _brokenDownDateToValue declarations.
As I see it, there isn't a proper way to decode their example. The example is insufficient. A dictionary should not create definitions using words that can't be found elsewhere in the dictionary.

flutter how to compare two different format phone numbers

I am trying to find if two phone numbers are same or not (Two same phone number may not be in the same format, as +919998245345 is same as 9998245345 and 99982 45345)
For this, you can use contains() dart string method. I have marked the trailing statement as bold, cos, it applies on the String. Make sure you get the number in String format, or convert it to String and then perform the operation.
Alogrithm
Convert the number to be compared to String, or get the number as String
Remove all the white spaces using this code, your_phone_number_variable.replaceAll(new RegExp(r"\s+"), ""). So that every number should be having no white spaces in between for smooth operation
Use contains() like this, number1.contains(number2)
Code
// this is a comparision between +919998245345 and other numbers
// you can play around and get what you want
void main() {
var _inputPhone = "+919998245345";
var _checkPhone = "9998245345";
var _anotherCheck = "99982 45345";
// checking that white space removal works or not
print(_anotherCheck.replaceAll(new RegExp(r"\s+"), ""));
// I have just removed the spaces from the number which had the white
// space, you can store the value using this code for every data
// for unknown data coming from server side or user side
_anotherCheck = _anotherCheck.replaceAll(new RegExp(r"\s+"), "");
if(_inputPhone.contains(_anotherCheck)){
print('99982 45345 and +919998245345 are same');
}
if(_inputPhone.contains(_checkPhone)){
print('9998245345 and +919998245345 are same');
}
}
Output
9998245345
99982 45345 and +919998245345 are same
9998245345 and +919998245345 are same
void main() {
print(isSame('9998245345', '+91999824 5345'));
}
bool isSame(String number1, String number2) {
number1 = number1.replaceAll(' ', '');
number2 = number2.replaceAll(' ', '');
int len1 = number1.length;
int len2 = number2.length;
number1 = number1.substring(len1-10, len1);
number2 = number2.substring(len2-10, len2);
return number1 == number2;
}
I think this is the simple and best solution to chnage format of phone
String changeFormat(String phone) {
phone = phone.replaceAll(" ", "");
if (phone.startsWith("+")) {
return "0" + phone.substring(3);
} else {
return phone;
}
}

Dart/Flutter - How to avoid auto rounding done by NumberFormat.compactCurrency(locale: "en_IN").format() method while formatting a value?

Dart/Flutter - How to avoid auto rounding done by NumberFormat.compactCurrency(locale: "en_IN").format() method while formatting a value?
num value = 29886964;
NumberFormat numberFormat = NumberFormat.compactCurrency(locale: "en_IN");
String output = numberFormat.format(value);
Actual output = INR2.99Cr
Requirement/Expectation: INR2.98Cr
use NumberFormat.currency api
num value = 29886964;
NumberFormat numberFormat = NumberFormat.compactCurrency(locale: "en_IN" );
final count = math.pow(10 , (value.toString().length - numberFormat.significantDigits));
var result = value / count;
String output = numberFormat.format(result.floor() * count);
print(output);
value : INR2.98Cr
The Accepted answer didn't work for me, unfortunately.
So, this is my answer.
extension DoubleExtension on double {
String get formattedCurrency {
final formatter = NumberFormat.currency(symbol: '\$', decimalDigits: 2);
return formatter.format(this);
}
// Another way around
String get formattedCurrency_2 {
final formatter = NumberFormat('###.0#');
return formatter.format(this);
}
}
and you can use the extension this way:
<your_double_number>.formattedCurrency;
Don't forget to import the extension in your class.
For more info about the configuration please look at this document:
https://api.flutter.dev/flutter/intl/NumberFormat-class.html