Java实现Oracle的to_char函数

/**
     * 将int、long、double、float、String、Date等类型format成字符类型
     *
     * 一、数字format格式处理:
     * 01)99.99的实现,小数位四舍五入不够位数补0,整数位超出位数补空格;
     * 02)00.00的实现,小数位四舍五入不够位数补0,整数位超出位数补0;
     * 03)9099.99的实现,小数位四舍五入不够位数补0,整数位超出位数的长度 - indexOf("0")的长度补0,剩余位数补空格;
     * 04)FM99.99:去除整数位补位的空格和小数位补位的0
     * 05)FM99099.99:去除整数位补位的空格和小数位补位的0
     * 06)FM99099.99099:去除整数位补位的空格和从小数点最右边那个0之后的9补位的0
     * 07)9G999或9G09G99G9G:分组处理(format带G不带小数),只要是带G的地方就替换为,号,在补0之后补空格之前处理。format从左往右出现第一个0之前的补空格中的G不做处理。固定位替换没有出现的位置不做替换和java中的DecimalFormat有所区别。G分组和,号分组不可同时出现。
     * 08)9,999.99:分组(千)分隔符处理,和上面G分组处理一样,只是,号分组format可带小数部分,要做特殊处。G分组和,号分组不可同时出现。
     * 09)999D999:小数点,按照正常.处理,但是含D不含.
     * 10)999S或S999:带-或者+的处理,在出现在末尾就将-或者+放数字末尾,出现在首位负数不做处理,整数没有带+号的得带上。S只能出现在首尾位置且只能出现一次。
     * 11)999MI:如果数字 < 0 将负号置于末尾位置,MI与S不能同时出现;
     * 12)999PR:尖括号内负值,不能和S、MI同时存在,且只能出现在末尾位置,如果转换的数字为负数则去掉负号然后<>括起来;
     * 13)L999:货币符号(使用本地化),在数字前面加上本地化的货币化符号,只能出现在首位位置;
     * 14)RN:将阿拉伯数字转为罗马数字(输入在 1 和 3999 之间,否则返回:###############);
     * 15)99V999:移动n位小数,不能和D、.符号共存,最终可以将V换成.计算后再去掉.符号即为移动的位数;
     *
     * 二、日期format格式处理:
     * 01)年份:
     *     Y,YYY:四位带逗号的年,如:2,018
     *     YYYY:四位的年,如:2018
     *     YYY:年的后三位,如:018
     *     YY:年的后两位,如:18
     *     Y:年的最后一位,如:8
     * 02)月份(中文下取值都一样,都是:十一月):
     *     month:全长小写月份名,如:november
     *     Month:全长混合大小写月份名,如:November
     *     MONTH:全长大写月份名,如:NOVEMBER
     *     mon:小写缩写月份名,如:nov
     *     Mon:缩写混合大小写月份名,如:Nov
     *     MON:大写缩写月份名,如:NOV
     *     MM:月份 (01-12) ,如:08、11
     * 03)日:
     *     DDD:一年里的日子(001-366) ,如:311
     *     DD:一个月里的日子(01-31) ,如:07
     *     D:一周里的日子(1-7;SUN=1),如:4
     * 04)时:
     *     HH、HH12:一天的小时数 (01-12) 12小时制,如:02
     *     HH24:一天的小时数 (00-23) 24小时制,如:15
     * 05)分:
     *     MI:分钟 (00-59),如:50
     * 06)秒
     *     SS:秒 (00-59),如:12
     * 07)星期(中文下都一样,取值都是:星期四):
     *     DAY:全长大写日期名,如:THURSDAY
     *     Day:全长混合大小写日期名,如:Thursday
     *     day:全长小写日期名,如:thursday
     *     DY:缩写大写日期名,如:THU
     *     Dy:缩写混合大小写日期名,如:Thu
     *     dy:缩写小写日期名,如:thu
     * 08)午夜00:00到当前时间的秒
     *     SSSSS:午夜后的秒 (0-86399),如:55302
     * 09)正午标识
     *     AM、A.M.、am、a.m.、PM、P.M.、pm、p.m.:如:中文显示:上午、下午;英文显示:给定值相同的格式和大小写,只是am、pm的区别
     * 10)年标识
     *     BC、B.C.、bc、b.c.、AD、A.D.、ad、a.d.:如:中文显示:公元、公元前,英文显示:AD、BC
     * 11)当月第几周
     *     W:如:1
     * 12)当年第几周
     *     WW:如:45
     * 13)世纪(2 位)
     *     CC:如:21
     * 14)儒略日
     *     J:Julian 日期(自公元前4712年1月1日来的日期),如:2458430
     * 15)季度
     *     Q:当前是第几季度,例如:4
     * 16)罗马数字的月份
     *     RM:大写罗马月份,如:XI
     *     rm:小写罗马月份,如:xi
     *
     *
     *
     * @return 转换后的字符串
     */
    public static <T> String to_char(T data, String format) {
        if(data instanceof Date || data instanceof Instant || data instanceof LocalDateTime) {//日期格式化
            LocalDateTime localDateTime;
            if(data instanceof Date) {
                localDateTime = LocalDateTime.ofInstant(((Date) data).toInstant(), ZoneId.systemDefault());
            } else if(data instanceof Instant) {
                localDateTime = LocalDateTime.ofInstant(((Instant) data), ZoneId.systemDefault());
            } else {
                localDateTime = (LocalDateTime) data;
            }

            Locale locale = Locale.UK;

            //
            String year = String.valueOf(localDateTime.getYear());

            //月,如:十一月 November
            String month_full = localDateTime.getMonth().getDisplayName(TextStyle.FULL, locale);
            //月,如:十一月 Nov
            String month_short = localDateTime.getMonth().getDisplayName(TextStyle.SHORT, locale);
            //月,如:11
            String month_num = String.valueOf(localDateTime.getMonthValue() > 9 ? localDateTime.getMonthValue() : "0" + localDateTime.getMonthValue());

            //当月第几天,如:8
            String dayOfMonth = String.valueOf(localDateTime.getDayOfMonth() > 9 ? localDateTime.getDayOfMonth() : "0" + localDateTime.getDayOfMonth());
            //当年第几天,如:312
            String dayOfYear = String.valueOf(localDateTime.getDayOfYear());
            //当周第几天,如:5(localdatetime获取的都是本地化的,老外的一周是从周日开始的,所以加一)
            String dayOfWeek = String.valueOf(localDateTime.getDayOfWeek().getValue() + 1);

            //小时HH24
            String hour24 = String.valueOf(localDateTime.getHour() > 9 ? localDateTime.getHour() : "0" + localDateTime.getHour());
            //小时12
            int hour12_temp = localDateTime.getHour();
            if(localDateTime.getHour() > 12) {
                hour12_temp -= 12;
            }
            String hour12 = String.valueOf(hour12_temp > 9 ? hour12_temp : "0" + hour12_temp);

            //
            String minute = String.valueOf(localDateTime.getMinute() > 9 ? localDateTime.getMinute() : "0" + localDateTime.getMinute());

            //
            String second = String.valueOf(localDateTime.getSecond() > 9 ? localDateTime.getSecond() : "0" + localDateTime.getSecond());

            //星期
            String week_short = localDateTime.getDayOfWeek().getDisplayName(TextStyle.SHORT, locale);
            String week_full = localDateTime.getDayOfWeek().getDisplayName(TextStyle.FULL, locale);

            //午夜0点到现在的秒数
            String mid_second = String.valueOf(ChronoUnit.SECONDS.between(LocalDateTime.of(localDateTime.getYear(), localDateTime.getMonthValue(), localDateTime.getDayOfMonth(), 0, 0, 0), localDateTime));

            //正午标识AM or PM
            String high_noon_symbol = localDateTime.format(DateTimeFormatter.ofPattern("a", locale));
            String ampm_dot = high_noon_symbol;
            if(locale.getLanguage().equals("en")) {
                ampm_dot = (new StringBuilder(ampm_dot).insert(1, ".").insert(3, ".")).toString();
            }

            //世纪标识 AD or BC
            String century_symbol = localDateTime.format(DateTimeFormatter.ofPattern("G", locale));
            String adbc_dot = century_symbol;
            if(locale.getLanguage().equals("en")) {
                adbc_dot = (new StringBuilder(adbc_dot).insert(1, ".").insert(3, ".")).toString();
            }

            //当月第几周
            String weekOfMonth = localDateTime.format(DateTimeFormatter.ofPattern("W", locale));

            //当年第几周
            String weekOfYear = localDateTime.format(DateTimeFormatter.ofPattern("w", locale));

            //获取给定的时间是第几世纪
            String century = String.valueOf((int) Math.ceil(localDateTime.getYear() / 100.0));

            //儒略日
            int a = (14 - localDateTime.getMonthValue()) / 12;
            int y = localDateTime.getYear() + 4800 - a;
            int m = localDateTime.getMonthValue() + 12 * a - 3;
            String julian = String.valueOf(localDateTime.getDayOfMonth() + (153 * m + 2) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 32045);

            //季度
            String quarterOfYear = localDateTime.format(DateTimeFormatter.ofPattern("Q", locale));

            //罗马数字的月份
            String rm_month = to_char(localDateTime.getMonthValue(), "RN");

            String date_format = format.replaceAll("((?i)Y),(?i)YYY", new StringBuilder(year).insert(1, ",").toString())//处理年:y,yyy 带逗号的年(4 和更多位)
                    .replaceAll("(?i)YYYY", year)//处理年:yyyy 年(4和更多位)
                    .replaceAll("(?i)YYY", year.substring(1))//处理年:yyy 年的后三位
                    .replaceAll("(?i)YY", year.substring(2))//处理年:yy 年的后两位
                    .replaceAll("(?<!DA|Da|da|D|d)(?i)Y", year.substring(3))//处理年:y 年的最后一位
                    .replaceAll("(?i)J", julian)//Julian日(自公元前4712年1月1日来的日期)
                    .replaceAll("MONTH", month_full.toUpperCase())//处理月份:MONTH 全长大写月份名(9字符)
                    .replaceAll("Month", month_full)//处理月份:Month 全长混合大小写月份名(9字符)
                    .replaceAll("month", month_full.toLowerCase())//处理月份:month 全长小写月份名(9字符)
                    .replaceAll("MON", month_short.toUpperCase())//处理月份:MON 大写缩写月份名(3字符)
                    .replaceAll("Mon", month_short)//处理月份:Mon 缩写混合大小写月份名(3字符)
                    .replaceAll("mon", month_short.toLowerCase())//处理月份:mon 小写缩写月份名(3字符)
                    .replaceAll("(?i)MM", month_num)//处理月:MM 月份 (01-12)
                    .replaceAll("(?i)DDD", dayOfYear)//处理日:DDD 一年里的日子(001-366)
                    .replaceAll("(?i)DD", dayOfMonth)//处理日:DD 一个月里的日子(01-31)
                    .replaceAll("(?<!a|A)(?i)D(?!ay|y|\\.|ecember)", dayOfWeek)//处理日:D 一周里的日子(1-7;SUN=1)
                    .replaceAll("(?i)HH24", hour24)//小时处理:HH24 一天的小时数 (00-23)
                    .replaceAll("(?i)HH12", hour12)//小时处理:HH12 一天的小时数 (01-12)
                    .replaceAll("(?i)HH", hour12)//小时处理:HH 一天的小时数 (01-12)
                    .replaceAll("(?i)MI", minute)//分钟处理:MI 分钟 (00-59)
                    .replaceAll("(?i)SSSSS",  mid_second)//处理午夜后的秒:SSSSS (0-86399)
                    .replaceAll("(?i)SS", second)//秒处理:SS 秒 (00-59)
                    .replaceAll("WW", weekOfYear)//当年第几周
                    .replaceAll("W", weekOfMonth)//当月第几周
                    .replaceAll("DAY", week_full.toUpperCase())//处理星期:DAY 全长大写日期名(9字符)
                    .replaceAll("day", week_full.toLowerCase())//处理星期:day 全长小写日期名(9字符)
                    .replaceAll("Day", week_full)//处理星期:Day 全长混合大小写日期名(9字符)
                    .replaceAll("DY", week_short.toUpperCase())//处理星期:DY 缩写大写日期名(3字符)
                    .replaceAll("Dy", week_short)//处理星期:Dy 缩写混合大小写日期名(3字符)
                    .replaceAll("dy", week_short.toLowerCase())//处理星期:dy 缩写小写日期名(3字符)
                    .replaceAll("AM", high_noon_symbol)//正午标识:AM
                    .replaceAll("A.M.", ampm_dot)//正午标识:A.M.
                    .replaceAll("am", high_noon_symbol.toLowerCase())//正午标识:am
                    .replaceAll("a.m.", ampm_dot.toLowerCase())//正午标识:a.m.
                    .replaceAll("PM", high_noon_symbol)//正午标识:PM
                    .replaceAll("P.M.", ampm_dot)//正午标识:P.M.
                    .replaceAll("pm", high_noon_symbol.toLowerCase())//正午标识:pm
                    .replaceAll("p.m.", ampm_dot.toLowerCase())//正午标识:p.m.
                    .replaceAll("AM", high_noon_symbol)//正午标识:AM
                    .replaceAll("BC", century_symbol)//世纪标识:BC
                    .replaceAll("bc", century_symbol.toLowerCase())//世纪标识:bc
                    .replaceAll("B.C.", adbc_dot)//世纪标识:B.C.
                    .replaceAll("b.c.", adbc_dot.toLowerCase())//世纪标识:b.c.
                    .replaceAll("AD", century_symbol)//世纪标识:AD
                    .replaceAll("A.D.", adbc_dot)//世纪标识:A.D.
                    .replaceAll("ad", century_symbol.toLowerCase())//世纪标识:ad
                    .replaceAll("a.d.", adbc_dot.toLowerCase())//世纪标识:a.d.
                    .replaceAll("(?i)CC", century)//世纪:CC
                    .replaceAll("(?i)Q", quarterOfYear)//当前是第几季度:Q
                    .replaceAll("RM", rm_month)//大写罗马月份:RM
                    .replaceAll("rm", rm_month.toLowerCase())//小写罗马月份:rm
                    ;

            return date_format;
        } else {//数字格式化
            try {
                format = format.toUpperCase();

                //format合法性判断:FM只能出现在首位位置、G不能出现在首位位置
                if(!format.matches("^[FM]*[0|9|.|,|PR|S|L|D|G|MI|RN|V]*")) {
                    throw new IllegalArgumentException("无效的数字格式模型");
                }

                //判断是否含G(分组)处理,含G不含小数位,且和,不能同时存在
                if(format.contains("G") && (format.contains(".") || format.contains(",") || format.startsWith("G"))) {
                    throw new IllegalArgumentException("无效的数字格式模型");
                }

                //判断D和.不能同时存在,且只能出现一次
                if(format.contains("D") && (CommonUtil.count(format, "D") > 1 || format.contains("."))) {
                    throw new IllegalArgumentException("无效的数字格式模型");
                }

                //判断S只能出现在首位位置且只能出现一次
                if(format.contains("S") && (CommonUtil.count(format, "S") > 1 || (!format.startsWith("S") && !format.endsWith("S")))) {
                    throw new IllegalArgumentException("无效的数字格式模型");
                }

                //判断MI和S不能同时出现,且只能出现在末尾位置
                if(format.contains("MI") && (CommonUtil.count(format, "MI") > 1 || format.contains("S") || !format.endsWith("MI"))) {
                    throw new IllegalArgumentException("无效的数字格式模型");
                }

                //判断PR和S、MI不能同时存在,且只能出现在末尾位置
                if(format.contains("PR") && (CommonUtil.count(format, "PR") > 1 || format.contains("S") || format.contains("MI") || !format.endsWith("PR"))) {
                    throw new IllegalArgumentException("无效的数字格式模型");
                }

                //判断L货币符号,只能出现在首位位置
                if(format.contains("L") && !format.startsWith("L")) {
                    throw new IllegalArgumentException("无效的数字格式模型");
                }

                //判断V,不能和D、.符号共存,且只能出现一次
                if(format.contains("V") && (CommonUtil.count(format, "V") > 1 || format.contains("D") || format.contains("."))) {
                    throw new IllegalArgumentException("无效的数字格式模型");
                }

                //处理D,换成.运算
                format = format.replace("D", ".");

                //处理V,换成.运算
                boolean v_symbol = false;
                if(format.contains("V")) {
                    v_symbol = true;
                    format = format.replace("V", ".");
                }

                String data_str = to_char(data);

                //处理RN,转换为罗马数字
                if (format.equals("RN")) {
                    int[] numArray = new int[]{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
                    String[] romaArray = new String[]{"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
                    StringBuffer stringBuffer = new StringBuffer();

                    int num = (int) Math.round(Double.valueOf(data_str));

                    if (num < 0 || num > 3999) {
                        return "###############";
                    }
                    for (int i = 0; i < numArray.length; i++) {
                        int temp = num / numArray[i];
                        while (temp > 0) {
                            stringBuffer.append(romaArray[i]);
                            temp--;
                        }
                        num = num % numArray[i];
                    }
                    return stringBuffer.toString();
                }

                //按照plsql执行结果,当format整数部分位数不够data整数部分位数的时候返回format整数位数+1位的# + format小数位+1的#
                String[] format_num = format.replaceAll("[A-Za-z,]", "").split("\\.");
                String[] data_num = data_str.replace("-", "").replace("+", "").split("\\.");
                if(format_num[0].length() < data_num[0].length()) {
                    String result = format_num[0].replaceAll("[9|0]", "#") + "#";
                    if(format_num.length == 2) {
                        result += format_num[1].replaceAll("[9|0]", "#") + "#";
                    }
                    return result;
                }

                //将9处理成#和0让DecimalFormat可以识别
                BigDecimal bigDecimal = new BigDecimal(data_str);
                String pattern = format_num[0].replace("9", "#").replace("0", "#");//#是不参与补位的
                if(format_num.length == 2) {
                    if (format.startsWith("FM")) {
                        //去除小数点后除0补位的0之后由9补位的0
                        pattern += "." + format_num[1].substring(0, format_num[1].lastIndexOf("0") + 1).replace("9", "0");
                        pattern += format_num[1].substring(format_num[1].lastIndexOf("0") + 1).replace("9", "#");
                    } else {
                        pattern += "." + format_num[1].replace("9", "0");//小数点右边转换成0好补位
                    }
                }
                DecimalFormat decimalFormat = new DecimalFormat(pattern);
                decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
                String result = decimalFormat.format(bigDecimal);

                //处理整数部位多余的9补空格、0补0
                int beyond_length = format_num[0].length() - data_num[0].length();//整数位格式化超出位数6 format=909909000000.00  data=123456.123456
                String sub_format = format_num[0].substring(0, beyond_length);//获取超出位数的格式字符0-6 sub_format=909909
                int zero_pos = sub_format.indexOf("0");//从左到右第一次出现0的位置 zero_pos=1
                int zero_patch_len = 0, blank_patch_len = 0;
                if (zero_pos > -1) {
                    zero_patch_len = sub_format.length() - zero_pos;//计算补0的个数 6 - 1 = 5
                }

                blank_patch_len = beyond_length - zero_patch_len;//计算补空格个数 6 - 5 = 1

                //整数位补0
                while (zero_patch_len > 0) {
                    if (result.contains("+")) {
                        result = result.replace("+", "+0");
                    } else if (result.contains("-")) {
                        result = result.replace("-", "-0");
                    } else {
                        result = "0" + result;
                    }
                    zero_patch_len -= 1;
                }

                //处理带G和,的分组
                int sub_index = 0, total_index = 0;
                //通过原始format中整数数字的位数和最终格式化后数字的整数位数对比获取真实的format的作用长度,也就是将format中的G对应到结果数字中的位置,并替换成,

                String integer_format = format.indexOf(".") == -1 ? format : format.substring(0, format.indexOf("."));//防止,号分组会出现小数位的问题

                for (int i = integer_format.toCharArray().length - 1; i >= 0 ; i--) {
                    if(Character.isDigit(integer_format.charAt(i))) {
                        sub_index += 1;
                    }
                    total_index += 1;
                    if(sub_index == result.replace("-", "").replace("+", "").split("\\.")[0].length()) {
                        break;
                    }
                }
                String format_temp = integer_format.substring((integer_format.length() - total_index));

                //将,号分组处理换成G分组一起处理
                format_temp = format_temp.replace(",", "G");

                int g_index = format_temp.indexOf("G");//G第一个出现的索引位置
                StringBuilder sb = new StringBuilder(result);
                while (g_index != -1) {
                    int insert_index = g_index;
                    if(sb.indexOf("-") != -1 || sb.indexOf("+") != -1) {
                        insert_index += 1;
                    }
                    sb.insert(insert_index, ",");
                    g_index = format_temp.indexOf("G", g_index + 1);//*从这个索引往后开始第一个出现的位置
                }
                result = sb.toString();

                System.out.println("format=" + format);

                //处理S,断定只出现首位位置
                if(format.startsWith("S")) {
                    if(!result.startsWith("+") && !result.startsWith("-")) {
                        result = "+" + result;
                    }
                } else if(format.endsWith("S")) {
                    if(!result.startsWith("+") && !result.startsWith("-")) {
                        result += "+";
                    } else if(result.startsWith("+")) {
                        result = result.replace("+", "");
                        result += "+";
                    } else if(result.startsWith("-")) {
                        result = result.replace("-", "");
                        result += "-";
                    }
                }

                //处理MI,断定只出现末尾位置,且为负数的时候才处理
                if(format.endsWith("MI") && result.startsWith("-")) {
                    result = result.replace("-", "");
                    result += "-";
                }

                //处理PR,断定只出现在末尾位置,且为负数的时候才做处理
                if(format.endsWith("PR") && result.startsWith("-")) {
                    result = result.replace("-", "");
                    result = "<" + result + ">";
                }

                //处理L,断定只出现在首位位置
                if(format.startsWith("L")) {
                    //获取本地货币符号
                    String currency_format = DecimalFormat.getCurrencyInstance(Locale.getDefault()).format(1);
                    String currency_symbol = currency_format.substring(0, 1);
                    if(result.startsWith("-")) {
                        result = result.replace("-", "-" + currency_symbol);
                    } else {
                        result = currency_symbol + result;
                    }
                }

                //处理V,上面是作为小数点处理的,只需要去掉小数点就相当于移动的小数
                if(v_symbol) {
                    result = result.replace(".", "");
                }

                //FM处理,判断是否去空格
                if (!format.startsWith("FM")) {
                    //最左边补空格
                    while (blank_patch_len > 0) {
                        result = " " + result;
                        blank_patch_len -= 1;
                    }
                }

                return result;
            } catch (NumberFormatException nfe) {
                throw new IllegalArgumentException("无效的数字");
            }
        }
    }
 
查看代码

 

posted @ 2018-11-09 17:30  天蝎(Scorpion)  阅读(468)  评论(0编辑  收藏  举报