All Downloads are FREE. Search and download functionalities are using the official Maven repository.

functionalj.lens.lenses.StringAccess Maven / Gradle / Ivy

There is a newer version: 1.0.17
Show newest version
// ============================================================================
// Copyright (c) 2017-2021 Nawapunth Manusitthipol (NawaMan - http://nawaman.net).
// ----------------------------------------------------------------------------
// MIT License
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ============================================================================
package functionalj.lens.lenses;

import static functionalj.functions.StrFuncs.toStr;
import static functionalj.lens.lenses.StringAccessHelper.fromString;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.ToIntFunction;
import java.util.stream.Stream;

import functionalj.function.Func1;
import functionalj.lens.lenses.java.time.LocalDateAccess;
import functionalj.lens.lenses.java.time.LocalDateTimeAccess;
import functionalj.list.FuncList;
import functionalj.result.Result;
import lombok.val;


class StringAccessHelper {
    
    static StringAccess $(Object ... objs) {
        return str -> {
            val eachToString = stringFrom(str);
            return Stream.of(objs).map(eachToString).collect(joining());
        };
    }
    
    static Func1 stringFrom(String str) {
        return each -> stringFrom(each, str);
    }
    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static String stringFrom(Object each, String str) {
        if (each instanceof Supplier) {
            Supplier supplier = (Supplier)each;
            Object   newValue = supplier.get();
            return toStr(newValue);
        }
        if (each instanceof Function) {
            Function function = (Function)each;
            Object   newValue = function.apply(str);
            return toStr(newValue);
        }
        return toStr(each);
    }
    
    @SuppressWarnings({ "rawtypes", "unchecked" })
    static Function fromString(Object object) {
        if (object instanceof AnyAccess) {
            return str -> ((AnyAccess) object).apply(str);
        }
        return __ -> object;
    }
    
}


/**
 * Classes implementing this interface know how to access to a String value.
 **/
@FunctionalInterface
public interface StringAccess 
                    extends 
                        ObjectAccess, 
                        ConcreteAccess> {
    
    public static  StringAccess of(Function accessToValue) {
        requireNonNull(accessToValue);
        
        if (accessToValue instanceof StringAccess) {
            return (StringAccess)accessToValue;
        }
        
        if (accessToValue instanceof Func1) {
            val func1  = (Func1)accessToValue;
            val access = (StringAccess)func1::applyUnsafe;
            return access;
        }
        
        val func   = (Function)accessToValue;
        val access = (StringAccess)(host -> func.apply(host));
        return access;
    }
    
    @Override
    public default StringAccess newAccess(Function access) {
        return access::apply;
    }
    
    //== functionalities ==
    
    public default CharacterAccessPrimitive charAt(int index) {
        return host -> {
            val  strValue  = apply(host);
            val charValue = strValue.charAt(index);
            return charValue;
        };
    }
    
    // Extra
    
    public default BooleanAccess thatIsBlank() {
        return booleanAccess(true, str->str.trim().isEmpty());
    }
    
    public default BooleanAccess thatIsNotBlank() {
        return booleanAccess(true, str->!str.trim().isEmpty());
    }
    
    // java.lang.String
    
    public default IntegerAccess compareToIgnoreCase(String anotherString) {
        return IntegerAccess.of(host -> {
            if (host == null)
                return (anotherString == null) ? 0 : -1;
            
            val value = apply(host);
            if (value == null)
                return (anotherString == null) ? 0 : -1;
            
            return value.compareToIgnoreCase(anotherString);
        });
    }
    public default IntegerAccess compareToIgnoreCase(Function anotherStringFunction) {
        return IntegerAccess.of(host -> {
            if (host == null)
                return 0;
            
            val value   = apply(host);
            val another = anotherStringFunction.apply(host);
            if (value == another)
                return 0;
            if (value == null)
                return -1;
            
            return value.compareToIgnoreCase(another);
        });
    }
    
    public default StringAccess concat(Object ... suffixes) {
        return stringAccess("", str -> {
            val eachToString = StringAccessHelper.stringFrom(str);
            String suffix = Stream.of(suffixes).map(eachToString).collect(joining());
            return str + suffix;
        });
    }
    
    public default StringAccess withPrefix(Object ... prefixes) {
        return stringAccess("", str -> {
            val eachToString = StringAccessHelper.stringFrom(str);
            String prefix = Stream.of(prefixes).map(eachToString).collect(joining());
            return prefix + str;
        });
    }
    public default StringAccess withSuffix(Object ... suffixes) {
        return stringAccess("", str -> {
            val eachToString = StringAccessHelper.stringFrom(str);
            String prefix = Stream.of(suffixes).map(eachToString).collect(joining());
            return str + prefix;
        });
    }
    public default StringAccess wrapBy(Object prefix, Object suffix) {
        return stringAccess("", str -> { 
            val eachToString = StringAccessHelper.stringFrom(str);
            String prefixStr = eachToString.apply(prefix);
            String suffixStr = eachToString.apply(suffix);
            return prefixStr + str + suffixStr;
        });
    }
    
    public default BooleanAccess thatEqualsIgnoreCase(String anotherString) {
        boolean isAnotherStringEmpty = (anotherString == null) || anotherString.isEmpty();
        return BooleanAccess.of(host -> {
            if (host == null)
                return isAnotherStringEmpty;
            
            val value = apply(host);
            if (value == null)
                return isAnotherStringEmpty;
            
            return value.equalsIgnoreCase(anotherString);
        });
    }
    public default BooleanAccess thatEqualsIgnoreCase(Function anotherStringFunction) {
        return BooleanAccess.of(host -> {
            val anotherString = anotherStringFunction.apply(host);
            boolean isAnotherStringEmpty = (anotherString == null) || anotherString.isEmpty();
            
            if (host == null)
                return isAnotherStringEmpty;
            
            val value = apply(host);
            if (value == null)
                return isAnotherStringEmpty;
            
            return value.equalsIgnoreCase(anotherString);
        });
    }
    
    public default BooleanAccess thatContentEquals(CharSequence charSequence) {
        return BooleanAccess.of(host -> {
            if (host == null)
                return (charSequence == null);
            
            val value = apply(host);
            if (value == null)
                return (charSequence == null);
            
            return value.contentEquals(charSequence);
        });
    }
    public default BooleanAccess thatContentEquals(Function anotherStringFunction) {
        return BooleanAccess.of(host -> {
            if (host == null)
                return false;
            
            val value   = apply(host);
            val another = anotherStringFunction.apply(host);
            if (value == another)
                return true;
            if (value == null)
                return false;
            
            return value.contentEquals(another);
        });
    }
    
    public default BooleanAccess thatContains(CharSequence charSequence) {
        return BooleanAccess.of(host -> {
            if (host == null)
                return false;
            
            val value = apply(host);
            if (value == null)
                return false;
            
            return value.contains(charSequence);
        });
    }
    public default BooleanAccess thatContains(Function anotherStringFunction) {
        return BooleanAccess.of(host -> {
            if (host == null)
                return false;
            
            val value   = apply(host);
            val another = anotherStringFunction.apply(host);
            if (value == another)
                return true;
            if (value == null)
                return false;
            
            return value.contains(another);
        });
    }
    
    public default BooleanAccess thatNotContains(CharSequence charSequence) {
        return BooleanAccess.of(host -> {
            if (host == null)
                return true;
            
            val value = apply(host);
            if (value == null)
                return true;
            
            return !value.contains(charSequence);
        });
    }
    public default BooleanAccess thatNotContains(Function anotherStringFunction) {
        return BooleanAccess.of(host -> {
            if (host == null)
                return true;
            
            val value = apply(host);
            if (value == null)
                return true;
            
            val another = anotherStringFunction.apply(host);
            return !value.contains(another);
        });
    }
    
    public default BooleanAccess thatContainsIgnoreCase(CharSequence charSequence) {
        return BooleanAccess.of(host -> {
            if (host == null)
                return false;
            
            val value = apply(host);
            if (value == null)
                return false;
            
            return value.toLowerCase().contains(charSequence.toString().toLowerCase());
        });
    }
    public default BooleanAccess thatContainsIgnoreCase(Function anotherStringFunction) {
        return BooleanAccess.of(host -> {
            if (host == null)
                return false;
            
            val value = apply(host);
            if (value == null)
                return false;
            
            val another = anotherStringFunction.apply(host);
            return value.toLowerCase().contains(another.toString().toLowerCase());
        });
    }
    
    public default BooleanAccess thatNotContainsIgnoreCase(CharSequence charSequence) {
        return BooleanAccess.of(host -> {
            if (host == null)
                return false;
            
            val value = apply(host);
            if (value == null)
                return false;
            
            return !value.toLowerCase().contains(charSequence.toString().toLowerCase());
        });
    }
    public default BooleanAccess thatNotContainsIgnoreCase(Function anotherStringFunction) {
        return BooleanAccess.of(host -> {
            if (host == null)
                return true;
            
            val value = apply(host);
            if (value == null)
                return true;
            
            val another = anotherStringFunction.apply(host);
            return !value.toLowerCase().contains(another.toString().toLowerCase());
        });
    }
    
    public default BooleanAccess thatEndsWith(String suffix) {
        boolean isSuffixEmpty = (suffix == null) || suffix.isEmpty();
        return BooleanAccess.of(host -> {
            if (host == null)
                return isSuffixEmpty;
            
            val value = apply(host);
            if (value == null)
                return isSuffixEmpty;
            
            return value.endsWith(suffix);
        });
    }
    public default BooleanAccess thatEndsWith(Function suffixFunction) {
        return BooleanAccess.of(host -> {
            val suffix = suffixFunction.apply(host);
            boolean isSuffixEmpty = (suffix == null) || suffix.isEmpty();
            
            if (host == null)
                return isSuffixEmpty;
            
            val value = apply(host);
            if (value == null)
                return isSuffixEmpty;
            
            return value.endsWith(suffix);
        });
    }
    
    /**
     * Giving the format create a final string using {@link String#format(String, Object...)}.
     * The string value from this access will be the first parameter for the formatting.
     * The given otherArgs will be the subsequence parameters for the formatting.
     * If any of the otherArgs is a Access, it will be applied with the string value.
     * 
     * Examples:
     * 
    *
  1. Simple: "Hello".formatWith("Word: %s"); will returns "Word: Hello"
  2. *
  3. More args: "Hello".formatWith("Word: %s %s.", "there"); will returns "Word: Hello there."
  4. *
  5. Access: "Hello".formatWith("Word: %s (%s).", $S.length()); will returns "Word: Hello (5)."
  6. *
**/ public default StringAccess formatWith(String format, Object... otherArgs) { return StringAccess.of(host -> { val value = (host == null) ? null : apply(host); val argStrs = FuncList.of(otherArgs).map(arg -> fromString(arg).apply(value)).prepend(value).toArray(); return String.format(format, argStrs); }); } /** * Similar to another formatWith method but the format is derived from the string value. **/ public default StringAccess formatWith(Function formatFunction, Object... otherArgs) { return StringAccess.of(host -> { val value = (host == null) ? null : apply(host); val format = formatFunction.apply(host); val argStrs = FuncList.of(otherArgs).map(arg -> fromString(arg).apply(value)).prepend(value).toArray(); return String.format(format, argStrs); }); } public default IntegerAccess indexOf(int chr) { return IntegerAccess.of(host -> { if (host == null) return -1; val value = apply(host); if (value == null) return -1; return value.indexOf(chr); }); } public default IntegerAccess indexOf(ToIntFunction chrFunction) { return IntegerAccess.of(host -> { if (host == null) return -1; val value = apply(host); if (value == null) return -1; val chr = chrFunction.applyAsInt(host); return value.indexOf(chr); }); } public default IntegerAccess indexOf(int ch, int fromIndex) { return intPrimitiveAccess(-1, str->str.indexOf(ch, fromIndex)); } public default IntegerAccess indexOf(String needle) { return IntegerAccess.of(host -> { if (host == null) return -1; val value = apply(host); if (value == null) return -1; return value.indexOf(needle); }); } public default IntegerAccess indexOf(Function needleFunction) { return IntegerAccess.of(host -> { if (host == null) return -1; val value = apply(host); if (value == null) return -1; val needle = needleFunction.apply(host); return value.indexOf(needle); }); } public default IntegerAccess indexOf(String needle, int fromIndex) { return intPrimitiveAccess(-1, str->str.indexOf(needle, fromIndex)); } public default BooleanAccess thatIsEmpty() { return booleanAccess(true, str->str.isEmpty()); } public default BooleanAccess thatIsNotEmpty() { return booleanAccess(true, str->!str.isEmpty()); } public default IntegerAccess lastIndexOf(int ch) { return IntegerAccess.of(host -> { if (host == null) return -1; val value = apply(host); if (value == null) return -1; return value.indexOf(ch); }); } public default IntegerAccess lastIndexOf(ToIntFunction chrFunction) { return IntegerAccess.of(host -> { if (host == null) return -1; val value = apply(host); if (value == null) return -1; val chr = chrFunction.applyAsInt(host); return value.lastIndexOf(chr); }); } public default IntegerAccess lastIndexOf(int ch, int fromIndex) { return intPrimitiveAccess(-1, str->str.lastIndexOf(ch, fromIndex)); } public default IntegerAccess lastIndexOf(String needle) { return IntegerAccess.of(host -> { if (host == null) return -1; val value = apply(host); if (value == null) return -1; return value.lastIndexOf(needle); }); } public default IntegerAccess lastIndexOf(Function needleFunction) { return IntegerAccess.of(host -> { if (host == null) return -1; val value = apply(host); if (value == null) return -1; val needle = needleFunction.apply(host); return value.lastIndexOf(needle); }); } public default IntegerAccess lastIndexOf(String needle, int fromIndex) { return intPrimitiveAccess(-1, str->str.lastIndexOf(needle, fromIndex)); } public default IntegerAccess length() { return IntegerAccess.of(host -> { if (host == null) return 0; val value = apply(host); if (value == null) return 0; return value.length(); }); } public default BooleanAccess thatMatches(String regex) { return BooleanAccess.of(host -> { if (host == null) return "".matches(regex); val value = apply(host); if (value == null) return "".matches(regex); return value.matches(regex); }); } public default BooleanAccess thatMatches(Function regexFunction) { return BooleanAccess.of(host -> { val regex = regexFunction.apply(host); if (host == null) return "".matches(regex); val value = apply(host); if (value == null) return "".matches(regex); return value.matches(regex); }); } public default BooleanAccess thatMatchesIgnoreCase(String regex) { return BooleanAccess.of(host -> { val lowerCaseRegEx = regex.toLowerCase(); if (host == null) return "".matches(lowerCaseRegEx); val value = apply(host); if (value == null) return "".matches(lowerCaseRegEx); return value.toLowerCase().matches(lowerCaseRegEx); }); } public default BooleanAccess thatMatchesIgnoreCase(Function regexFunction) { return BooleanAccess.of(host -> { val regex = regexFunction.apply(host); val lowerCaseRegEx = regex.toLowerCase(); if (host == null) return "".matches(lowerCaseRegEx); val value = apply(host); if (value == null) return "".matches(lowerCaseRegEx); return value.toLowerCase().matches(lowerCaseRegEx); }); } public default StringAccess replace(char oldChar, char newChar) { return stringAccess(null, str->str.replace(oldChar, newChar)); } public default StringAccess replace(CharSequence target, CharSequence replacement) { return stringAccess(null, str->str.replace(target, replacement)); } public default StringAccess replaceAll(String regEx, String replacement) { return StringAccess.of(host -> { if (host == null) return null; val value = apply(host); if (value == null) return null; return value.replaceAll(regEx, replacement); }); } public default StringAccess replaceAll(Function regexFunction, Function replacementFunction) { return StringAccess.of(host -> { if (host == null) return null; val value = apply(host); if (value == null) return null; val regex = regexFunction .apply(host); val replacement = replacementFunction.apply(host); return value.replaceAll(regex, replacement); }); } public default StringAccess replaceFirst(String regEx, String replacement) { return StringAccess.of(host -> { if (host == null) return null; val value = apply(host); if (value == null) return null; return value.replaceFirst(regEx, replacement); }); } public default StringAccess replaceFirst(Function regexFunction, Function replacementFunction) { return StringAccess.of(host -> { if (host == null) return null; val value = apply(host); if (value == null) return null; val regex = regexFunction .apply(host); val replacement = replacementFunction.apply(host); return value.replaceFirst(regex, replacement); }); } public default FuncListAccess> split(String regex) { return FuncListAccess.of(host -> { val strValue = StringAccess.this.apply(host); return FuncList.from(strValue.split(regex)); }, func -> StringAccess.this.newAccess(func)); } public default FuncListAccess> split(Function regexFunction) { return FuncListAccess.of(host -> { val strValue = StringAccess.this.apply(host); val regex = regexFunction.apply(host); return FuncList.from(strValue.split(regex)); }, func -> StringAccess.this.newAccess(func)); } public default BooleanAccess thatStartsWith(String prefix) { return BooleanAccess.of(host -> { if (host == null) return false; val value = apply(host); if (value == null) return false; return value.startsWith(prefix); }); } public default BooleanAccess thatStartsWith(Function prefixFunction) { return BooleanAccess.of(host -> { if (host == null) return false; val value = apply(host); if (value == null) return false; val prefix = prefixFunction.apply(host); return value.startsWith(prefix); }); } public default BooleanAccess thatStartsWith(String prefix, int offset) { return booleanAccess(false, str->str.startsWith(prefix, offset)); } public default StringAccess substring(int beginIndex) { return StringAccess.of(host -> { if (host == null) return null; val value = apply(host); if (value == null) return null; return value.substring(beginIndex); }); } public default StringAccess substring(ToIntFunction beginIndexFunction) { return StringAccess.of(host -> { if (host == null) return null; val value = apply(host); if (value == null) return null; val beginIndex = beginIndexFunction.applyAsInt(host); return value.substring(beginIndex); }); } public default StringAccess substring(int beginIndex, int endIndex) { return stringAccess(null, str->str.substring(beginIndex, endIndex)); } public default StringAccess toLowerCase() { return stringAccess(null, str->str.toLowerCase()); } public default StringAccess toLowerCase(Locale locale) { return stringAccess(null, str->str.toLowerCase(locale)); } public default StringAccess toUpperCase() { return stringAccess(null, str->str.toUpperCase()); } public default StringAccess toUpperCase(Locale locale) { return stringAccess(null, str->str.toUpperCase(locale)); } public default StringAccess trim() { return stringAccess(null, str->str.trim()); } //== parse == //-- integer -- public default IntegerAccessPrimitive asInteger() { return host -> { val valueStr = apply(host); return Integer.parseInt(valueStr); }; } public default IntegerAccessPrimitive asInteger(int radix) { return host -> { val valueStr = apply(host); return Integer.parseInt(valueStr, radix); }; } public default ResultAccess> parseInteger() { return ResultAccess.of(host -> { val valueStr = apply(host); return Result.from(()->Integer.parseInt(valueStr)); }, func -> (IntegerAccessBoxed)(func::apply)); } public default ResultAccess> parseInteger(int radix) { return ResultAccess.of(host -> { val valueStr = apply(host); return Result.from(()->Integer.parseInt(valueStr, radix)); }, func -> (IntegerAccessBoxed)(func::apply)); } //-- long -- public default LongAccessPrimitive asLong() { return host -> { val valueStr = apply(host); return Long.parseLong(valueStr); }; } public default LongAccessPrimitive asLong(int radix) { return host -> { val valueStr = apply(host); return Long.parseLong(valueStr, radix); }; } public default ResultAccess> parseLong() { return ResultAccess.of(host -> { val valueStr = apply(host); return Result.from(()->Long.parseLong(valueStr)); }, func -> (LongAccessBoxed)(func::apply)); } public default ResultAccess> parseLong(int radix) { return ResultAccess.of(host -> { val valueStr = apply(host); return Result.from(()->Long.parseLong(valueStr, radix)); }, func -> (LongAccessBoxed)(func::apply)); } //-- double -- public default DoubleAccessPrimitive asDouble() { return host -> { val valueStr = apply(host); return Double.parseDouble(valueStr); }; } public default ResultAccess> parseDouble() { return ResultAccess.of(host -> { val valueStr = apply(host); return Result.from(()->Double.parseDouble(valueStr)); }, func -> (DoubleAccessBoxed)(func::apply)); } //-- big integer -- public default BigIntegerAccess asBigInteger() { return host -> { val valueStr = apply(host); return new BigInteger(valueStr); }; } public default ResultAccess> parseBigInteger() { return ResultAccess.of(host -> { val valueStr = apply(host); return Result.from(()->new BigInteger(valueStr)); }, func -> (BigIntegerAccess)(func::apply)); } //-- big decimal -- public default BigDecimalAccess asBigDecimal() { return host -> { val valueStr = apply(host); return new BigDecimal(valueStr); }; } public default ResultAccess> parseBigDecimal() { return ResultAccess.of(host -> { val valueStr = apply(host); return Result.from(()->new BigDecimal(valueStr)); }, func -> (BigDecimalAccess)(func::apply)); } //-- local date -- public default LocalDateAccess asLocalDate() { return host -> { val valueStr = apply(host); return LocalDate.parse(valueStr); }; } public default LocalDateAccess asLocalDate(DateTimeFormatter formatter) { return host -> { val valueStr = apply(host); return LocalDate.parse(valueStr, formatter); }; } public default LocalDateAccess asLocalDate(String formatterPattern) { val formatter = DateTimeFormatter.ofPattern(formatterPattern); return asLocalDate(formatter); } public default ResultAccess> parseLocalDate() { return ResultAccess.of(host -> { val valueStr = apply(host); return Result.from(()->LocalDate.parse(valueStr)); }, func -> (LocalDateAccess)(func::apply)); } public default ResultAccess> parseLocalDate(DateTimeFormatter formatter) { return ResultAccess.of(host -> { val valueStr = apply(host); return Result.from(()->LocalDate.parse(valueStr, formatter)); }, func -> (LocalDateAccess)(func::apply)); } public default ResultAccess> parseLocalDate(String formatterPattern) { val formatter = DateTimeFormatter.ofPattern(formatterPattern); return parseLocalDate(formatter); } //-- local date time -- public default LocalDateTimeAccess asLocalDateTime() { return host -> { val valueStr = apply(host); return LocalDateTime.parse(valueStr); }; } public default LocalDateTimeAccess asLocalDateTime(DateTimeFormatter formatter) { return host -> { val valueStr = apply(host); return LocalDateTime.parse(valueStr, formatter); }; } public default LocalDateTimeAccess asLocalDateTime(String formatterPattern) { val formatter = DateTimeFormatter.ofPattern(formatterPattern); return asLocalDateTime(formatter); } public default ResultAccess> parseLocalDateTime() { return ResultAccess.of(host -> { val valueStr = apply(host); return Result.from(()->LocalDateTime.parse(valueStr)); }, func -> (LocalDateTimeAccess)(func::apply)); } public default ResultAccess> parseLocalDateTime(DateTimeFormatter formatter) { return ResultAccess.of(host -> { val valueStr = apply(host); return Result.from(()->LocalDateTime.parse(valueStr, formatter)); }, func -> (LocalDateTimeAccess)(func::apply)); } public default ResultAccess> parseLocalDateTime(String formatterPattern) { val formatter = DateTimeFormatter.ofPattern(formatterPattern); return parseLocalDateTime(formatter); } //-- TODO Add Zoned date and stuff. }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy